mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-09 01:07:27 +08:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
168e5f0b12 | ||
|
|
9286caf900 | ||
|
|
b0647bedb6 | ||
|
|
f49a868707 | ||
|
|
28bca25092 | ||
|
|
0227d2b44a | ||
|
|
0d95b886bc | ||
|
|
9b61acd163 | ||
|
|
be134bbc6e | ||
|
|
c8d0463b9e | ||
|
|
871c2082a8 | ||
|
|
14b685850c | ||
|
|
3fbf473de2 | ||
|
|
8a3cec05b7 | ||
|
|
e3d81436d0 | ||
|
|
941a79ccc7 | ||
|
|
62902a561c | ||
|
|
1660bc5899 | ||
|
|
d577246d28 | ||
|
|
9fd626468e | ||
|
|
c51a1b4e85 | ||
|
|
0e42123417 | ||
|
|
e216e6144b | ||
|
|
b70c435a4a | ||
|
|
eb03d2be93 | ||
|
|
fcb5d264ef | ||
|
|
d617951e1f | ||
|
|
febf931f1a | ||
|
|
981961d6a1 | ||
|
|
a90380df4c | ||
|
|
4f66f492fc | ||
|
|
df181f104e | ||
|
|
a890a9af4a | ||
|
|
c6bb4c9afb | ||
|
|
98358ad216 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.log
|
||||
52
README.md
52
README.md
@@ -2,16 +2,24 @@
|
||||
一个微型的Arcaea本地服务器 A small local server for Arcaea
|
||||
|
||||
## 简介 Introduction
|
||||
这是基于Python以及Flask的微型本地Arcaea服务器,可以模拟游戏的主要功能,一时兴起在五天之内糊了出来。这可能是我第一次写这种大程序,若有不妥之处,敬请谅解。
|
||||
This is a small local Arcaea server based on Python and Flask, which can simulate the main functions of the game. I completed it on the spur of the moment in five days. This may be the first time I have written such a large program. Please understand if there is something wrong with it.
|
||||
这是基于Python以及Flask的微型本地Arcaea服务器,可以模拟游戏的主要功能。这可能是我第一次写这种大程序,若有不妥之处,敬请谅解。
|
||||
|
||||
本程序主要用于学习研究,不得用于任何商业行为,否则后果自负,这不是强制要求,只是一个提醒与警告。
|
||||
|
||||
This is a small local Arcaea server based on Python and Flask, which can simulate the main functions of the game. This may be the first time I have written such a large program. Please understand if there is something wrong with it.
|
||||
|
||||
This procedure is mainly used for study and research, and shall not be used for any commercial activities, otherwise the consequences will be borne by oneself. This is not a mandatory requirement, just a reminder and warning.
|
||||
|
||||
> 虽然看起来很蠢,但是可以用!
|
||||
> It looks stupid, but it works!
|
||||
|
||||
## 特性 Features
|
||||
有以下 We have:
|
||||
- 登录、注册 Login and registration
|
||||
- 多设备登录 Multi device login
|
||||
- 成绩上传 Score upload
|
||||
- PTT
|
||||
- 世界排名 Global rank
|
||||
- 排名 Rank
|
||||
- 好友系统 Friends
|
||||
- 数据同步 Data synchronization
|
||||
@@ -21,22 +29,21 @@ This is a small local Arcaea server based on Python and Flask, which can simulat
|
||||
- 单曲和曲包购买(没啥用) Single songs and song packs purchase(useless)
|
||||
- 奖励系统 Present system
|
||||
- 兑换码系统 Redeem code system
|
||||
- 全角色立绘 All character drawings
|
||||
- 角色技能 Character skills
|
||||
- 自定义角色属性 Customizable characters attributes
|
||||
- 角色系统 Character system
|
||||
- 全剧情解锁 Unlock all the stories
|
||||
- 后台查询 Background search
|
||||
- 后台自定义信息 Customize some things in the background
|
||||
- 成绩校验 Score check
|
||||
- 下载校验 Download check
|
||||
- 服务器日志 Server log
|
||||
|
||||
没有以下 We don't have:
|
||||
- 角色数值 Character characteristic value
|
||||
- 服务器安全性保证 Server security assurance
|
||||
|
||||
可能有问题 There may be problems:
|
||||
- Recent 30
|
||||
- 一些歌曲的解锁 Some songs' unlocking
|
||||
- 同设备多共存登录 Multiple app logins on the same device
|
||||
|
||||
## 说明 Statement
|
||||
只是很有趣,用处探索中。
|
||||
@@ -51,37 +58,29 @@ It is just so interesting. What it can do is under exploration.
|
||||
## 更新日志 Update log
|
||||
只保留最新版本 Only keep the latest version.
|
||||
|
||||
> 提醒:更新时请注意保留原先的数据库,以防数据丢失
|
||||
> 提醒:更新时请注意保留原先的数据库,以防数据丢失。
|
||||
>
|
||||
> 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.0
|
||||
- 适用于Arcaea 3.4.1版本 For Arcaea 3.4.1
|
||||
- 更新API接口至13 Update API interface to 13.
|
||||
### Version 2.6.1
|
||||
- 适用于Arcaea 3.7.0版本 For Arcaea 3.7.0
|
||||
- 更新了歌曲数据库 Update the song database.
|
||||
- 新增了兑换码系统 Add the redeem code system.
|
||||
- 优化了下载时文件MD5的读取速度 Optimize the reading speed of MD5 when downloading.
|
||||
- 新增初见保护 Add initial protection.
|
||||
- EX保护机制修改,现在重复歌曲若分数较高,会刷新r30中最早的记录,并保证ptt不下降,仍不清楚能否正常起效 EX protection mechanism has been modified. If the score of one repetitive song is higher, it will refresh the earliest record in r30 and ensure that PTT won't not drop. It is still unclear whether it can work normally.
|
||||
- 数据迁移机制修改,现在重复数据以旧数据库数据为准 The database migration mechanism has been modified. Now the duplicate data is subject to the old database data.
|
||||
- 机制修改,数据库缺少歌曲定数会当做Unrank处理 The mechanism has been modified. The lack of chart constant of songs in the database will be treated as unrank.
|
||||
- 后台新增用户密码修改、用户封禁和成绩清除 Add user password modification, user ban and score clearance in the background.
|
||||
- 游戏内数据同步将记录同步时间 Data synchronization in game will record synchronization time.
|
||||
- 修复了一些Bug Fix some bugs.
|
||||
- 新增活动图设置 Add available event maps setting.
|
||||
- 修复了一个Bug Fix a bug.
|
||||
- 添加了`user/me`接口 Add `user/me` interface.
|
||||
|
||||
> 提醒:本次更新针对了API接口更新,将无法兼容Arcaea 3.4.1以下版本
|
||||
>
|
||||
> Tips: This update includes API interface update, and will not be compatible with the version below Arcaea 3.4.1.
|
||||
|
||||
## 运行环境与依赖 Running environment and requirements
|
||||
- Windows操作系统 Windows operating system
|
||||
- Windows/Linux/Mac OS/Android
|
||||
- Python 3
|
||||
- Flask模块 Flask module
|
||||
- Charles
|
||||
- Flask module
|
||||
- Charles, IDA, proxy app... (optional)
|
||||
|
||||
<!--
|
||||
## 环境搭建 Environment construction
|
||||
[中文](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)
|
||||
-->
|
||||
|
||||
## 使用说明 Instruction for use
|
||||
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E)
|
||||
@@ -91,6 +90,7 @@ It is just so interesting. What it can do is under exploration.
|
||||
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E6%B3%A8%E6%84%8F)
|
||||
[English](https://github.com/Lost-MSth/Arcaea-server/wiki/Attentions)
|
||||
|
||||
|
||||
## 鸣谢 Thanks
|
||||
歌曲数据库来自 Using song database from
|
||||
[BotArcAPI releases](https://github.com/TheSnowfield/BotArcAPI/releases)
|
||||
|
||||
118
latest version/api/api_auth.py
Normal file
118
latest version/api/api_auth.py
Normal file
@@ -0,0 +1,118 @@
|
||||
import hashlib
|
||||
import time
|
||||
from server.sql import Connect
|
||||
import functools
|
||||
from setting import Config
|
||||
from flask import jsonify
|
||||
|
||||
|
||||
class User():
|
||||
# 用户类,当数据类型用
|
||||
def __init__(self, user_id=None, role='', power=[]):
|
||||
self.user_id = user_id
|
||||
self.role = role
|
||||
self.power = power
|
||||
|
||||
|
||||
def login():
|
||||
# 登录接口
|
||||
return {'token': 1}, 0
|
||||
|
||||
|
||||
def logout():
|
||||
# 登出接口
|
||||
pass
|
||||
|
||||
|
||||
def id_get_role_id(c, user_id):
|
||||
# user_id获取role_id
|
||||
role_id = 1
|
||||
c.execute('''select role_id from user_role where user_id = :a''',
|
||||
{'a': user_id})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
role_id = int(x[0])
|
||||
|
||||
return role_id
|
||||
|
||||
|
||||
def role_id_get_role(c, role_id):
|
||||
# role_id获取role
|
||||
role = ''
|
||||
c.execute('''select role_name from role where role_id = :a''',
|
||||
{'a': role_id})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
role = x[0]
|
||||
|
||||
return role
|
||||
|
||||
|
||||
def api_token_get_id(c, token):
|
||||
# api的token获取user_id
|
||||
user_id = None
|
||||
c.execute('''select user_id from api_login where token = :token''', {
|
||||
'token': token})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
user_id = x[0]
|
||||
|
||||
return user_id
|
||||
|
||||
|
||||
def get_role_power(c, role_id):
|
||||
# 获取role_id对应power,返回列表
|
||||
|
||||
role_power = []
|
||||
|
||||
c.execute('''select power_name from power where power_id in (select power_id from role_power where role_id=:a)''', {
|
||||
'a': role_id})
|
||||
x = c.fetchall()
|
||||
for i in x:
|
||||
role_power.append(i[0])
|
||||
|
||||
return role_power
|
||||
|
||||
|
||||
def role_required(request, power=[]):
|
||||
# api token验证,写成了修饰器
|
||||
def decorator(view):
|
||||
@functools.wraps(view)
|
||||
def wrapped_view(*args, **kwargs):
|
||||
|
||||
try:
|
||||
request.json # 检查请求json格式
|
||||
except:
|
||||
return jsonify({'status': 400, 'code': -1, 'data': {}, 'msg': 'Payload must be a valid json'})
|
||||
|
||||
if not 'Token' in request.headers:
|
||||
return jsonify({'status': 401, 'code': -1, 'data': {}, 'msg': 'No Token'})
|
||||
|
||||
user = User()
|
||||
if Config.API_TOKEN == request.headers['Token'] and Config.API_TOKEN != '':
|
||||
user.user_id = 0
|
||||
elif power == []:
|
||||
return jsonify({'status': 403, 'code': -1, 'data': {}, 'msg': 'No permission'})
|
||||
else:
|
||||
with Connect() as c:
|
||||
user.user_id = api_token_get_id(
|
||||
c, request.headers['Token'])
|
||||
if user.user_id is None:
|
||||
return jsonify({'status': 404, 'code': -1, 'data': {}, 'msg': ''})
|
||||
|
||||
role_id = id_get_role_id(c, user.user_id)
|
||||
user.role = role_id_get_role(c, role_id)
|
||||
user.role_power = get_role_power(c, role_id)
|
||||
|
||||
f = False
|
||||
for i in power:
|
||||
if i in user.role_power:
|
||||
f = True
|
||||
break
|
||||
if not f:
|
||||
return jsonify({'status': 403, 'code': -1, 'data': {}, 'msg': 'No permission'})
|
||||
|
||||
return view(user, *args, **kwargs)
|
||||
|
||||
return wrapped_view
|
||||
return decorator
|
||||
15
latest version/api/api_code.py
Normal file
15
latest version/api/api_code.py
Normal file
@@ -0,0 +1,15 @@
|
||||
def code_get_msg(code):
|
||||
# api接口code获取msg,返回字符串
|
||||
msg = {
|
||||
'0': '',
|
||||
'-1': 'See status code',
|
||||
'-2': 'No data',
|
||||
'-3': 'No data or user',
|
||||
'-4': 'No user_id',
|
||||
'-101': 'Wrong data type',
|
||||
'-102': 'Wrong query parameter',
|
||||
'-103': 'Wrong sort parameter',
|
||||
'-104': 'Wrong sort order parameter'
|
||||
}
|
||||
|
||||
return msg[str(code)]
|
||||
223
latest version/api/api_main.py
Normal file
223
latest version/api/api_main.py
Normal file
@@ -0,0 +1,223 @@
|
||||
from flask import (
|
||||
Blueprint, request, jsonify
|
||||
)
|
||||
import api.api_auth
|
||||
import api.users
|
||||
import api.songs
|
||||
from api.api_code import code_get_msg
|
||||
|
||||
|
||||
bp = Blueprint('api', __name__, url_prefix='/api/v1')
|
||||
|
||||
|
||||
def get_query_parameter(request, query_able=[], sort_able=[]):
|
||||
# 提取查询请求参数,返回四个参数和code
|
||||
|
||||
limit = -1
|
||||
offset = 0
|
||||
query = {} # {'name': 'admin'}
|
||||
sort = [] # [{'column': 'user_id', 'order': 'ASC'}, ...]
|
||||
|
||||
if 'limit' in request.json:
|
||||
try:
|
||||
limit = int(request.json['limit'])
|
||||
except:
|
||||
return -1, 0, {}, {}, -101
|
||||
if 'offset' in request.json:
|
||||
try:
|
||||
offset = int(request.json['offset'])
|
||||
except:
|
||||
return -1, 0, {}, {}, -101
|
||||
if 'query' in request.json:
|
||||
query = request.json['query']
|
||||
for i in query:
|
||||
if i not in query_able:
|
||||
return -1, 0, {}, {}, -102
|
||||
if 'sort' in request.json:
|
||||
sort = request.json['sort']
|
||||
for i in sort:
|
||||
if 'column' not in i or i['column'] not in sort_able:
|
||||
return -1, 0, {}, {}, -103
|
||||
if not 'order' in i:
|
||||
i['order'] = 'ASC'
|
||||
else:
|
||||
if i['order'] not in ['ASC', 'DESC']:
|
||||
return -1, 0, {}, {}, -104
|
||||
|
||||
return limit, offset, query, sort, 0
|
||||
|
||||
|
||||
@bp.route('/')
|
||||
def ping():
|
||||
return jsonify({'status': 200, 'code': 0, 'data': {}, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/token', methods=['POST'])
|
||||
def token_post():
|
||||
# 登录,获取token
|
||||
|
||||
if 'auth' in request.json:
|
||||
data, code = api.api_auth.login(
|
||||
request.json['auth'], request.remote_addr)
|
||||
if code < 0:
|
||||
return jsonify({'status': 200, 'code': code, 'data': {}, 'msg': code_get_msg(code)})
|
||||
else:
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
else:
|
||||
return jsonify({'status': 401, 'code': -1, 'data': {}, 'msg': 'No authentication'})
|
||||
|
||||
|
||||
@bp.route('/token', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select_me', 'select'])
|
||||
def token_get(user):
|
||||
# 判断登录有效性
|
||||
return jsonify({'status': 200, 'code': 0, 'data': {}, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/token', methods=['DELETE'])
|
||||
@api.api_auth.role_required(request, ['change_me', 'select_me', 'select'])
|
||||
def token_delete(user):
|
||||
# 登出
|
||||
return jsonify({'status': 200, 'code': 0, 'data': {}, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/users', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select'])
|
||||
def users_get(user):
|
||||
# 查询全用户信息
|
||||
|
||||
limit, offset, query, sort, code = get_query_parameter(request, ['user_id', 'name', 'user_code'], [
|
||||
'user_id', 'name', 'user_code', 'join_date', 'rating_ptt', 'time_played', 'ticket', 'world_rank_score'])
|
||||
if code < 0:
|
||||
return jsonify({'status': 200, 'code': code, 'data': {}, 'msg': code_get_msg(code)})
|
||||
|
||||
data = api.users.get_users(limit, offset, query, sort)
|
||||
|
||||
if not data:
|
||||
return jsonify({'status': 200, 'code': -2, 'data': {}, 'msg': code_get_msg(-2)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/users/<int:user_id>', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select', 'select_me'])
|
||||
def users_user_get(user, user_id):
|
||||
# 查询用户信息
|
||||
|
||||
if user_id == 'me':
|
||||
user_id = user.user_id
|
||||
|
||||
if user_id <= 0:
|
||||
return jsonify({'status': 200, 'code': -4, 'data': {}, 'msg': code_get_msg(-4)})
|
||||
|
||||
if user_id != user.user_id and not 'select' in user.power and user.user_id != 0: # 查别人需要select权限
|
||||
return jsonify({'status': 403, 'code': -1, 'data': {}, 'msg': 'No permission'})
|
||||
|
||||
data = api.users.get_user_info(user_id)
|
||||
|
||||
if not data:
|
||||
return jsonify({'status': 200, 'code': -3, 'data': {}, 'msg': code_get_msg(-3)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/users/<int:user_id>/b30', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select', 'select_me'])
|
||||
def users_user_b30_get(user, user_id):
|
||||
# 查询用户b30
|
||||
|
||||
if user_id == 'me':
|
||||
user_id = user.user_id
|
||||
|
||||
if user_id <= 0:
|
||||
return jsonify({'status': 200, 'code': -4, 'data': {}, 'msg': code_get_msg(-4)})
|
||||
|
||||
if user_id != user.user_id and not 'select' in user.power and user.user_id != 0: # 查别人需要select权限
|
||||
return jsonify({'status': 403, 'code': -1, 'data': {}, 'msg': 'No permission'})
|
||||
|
||||
data = api.users.get_user_b30(user_id)
|
||||
|
||||
if data['data'] == []:
|
||||
return jsonify({'status': 200, 'code': -3, 'data': {}, 'msg': code_get_msg(-3)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/users/<int:user_id>/best', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select', 'select_me'])
|
||||
def users_user_best_get(user, user_id):
|
||||
# 查询用户所有best成绩
|
||||
|
||||
if user_id == 'me':
|
||||
user_id = user.user_id
|
||||
|
||||
if user_id <= 0:
|
||||
return jsonify({'status': 200, 'code': -4, 'data': {}, 'msg': code_get_msg(-4)})
|
||||
|
||||
if user_id != user.user_id and not 'select' in user.power and user.user_id != 0: # 查别人需要select权限
|
||||
return jsonify({'status': 403, 'code': -1, 'data': {}, 'msg': 'No permission'})
|
||||
|
||||
limit, offset, query, sort, code = get_query_parameter(request, ['song_id', 'difficulty'], [
|
||||
'song_id', 'difficulty', 'score', 'time_played', 'rating'])
|
||||
if code < 0:
|
||||
return jsonify({'status': 200, 'code': code, 'data': {}, 'msg': code_get_msg(code)})
|
||||
|
||||
data = api.users.get_user_best(user_id, limit, offset, query, sort)
|
||||
|
||||
if data['data'] == []:
|
||||
return jsonify({'status': 200, 'code': -3, 'data': {}, 'msg': code_get_msg(-3)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/users/<int:user_id>/r30', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select', 'select_me'])
|
||||
def users_user_r30_get(user, user_id):
|
||||
# 查询用户r30
|
||||
|
||||
if user_id == 'me':
|
||||
user_id = user.user_id
|
||||
|
||||
if user_id <= 0:
|
||||
return jsonify({'status': 200, 'code': -4, 'data': {}, 'msg': code_get_msg(-4)})
|
||||
|
||||
if user_id != user.user_id and not 'select' in user.power and user.user_id != 0: # 查别人需要select权限
|
||||
return jsonify({'status': 403, 'code': -1, 'data': {}, 'msg': 'No permission'})
|
||||
|
||||
data = api.users.get_user_r30(user_id)
|
||||
|
||||
if data['data'] == []:
|
||||
return jsonify({'status': 200, 'code': -3, 'data': {}, 'msg': code_get_msg(-3)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/songs/<string:song_id>', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select', 'select_song_info'])
|
||||
def songs_song_get(user, song_id):
|
||||
# 查询歌曲信息
|
||||
|
||||
data = api.songs.get_song_info(song_id)
|
||||
|
||||
if not data:
|
||||
return jsonify({'status': 200, 'code': -2, 'data': {}, 'msg': code_get_msg(-2)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
|
||||
|
||||
@bp.route('/songs', methods=['GET'])
|
||||
@api.api_auth.role_required(request, ['select', 'select_song_info'])
|
||||
def songs_get(user):
|
||||
# 查询全歌曲信息
|
||||
|
||||
limit, offset, query, sort, code = get_query_parameter(request, ['sid', 'name_en', 'name_jp', 'pakset', 'artist'], [
|
||||
'sid', 'name_en', 'name_jp', 'pakset', 'artist', 'date', 'rating_pst', 'rating_prs', 'rating_ftr', 'rating_byn'])
|
||||
if code < 0:
|
||||
return jsonify({'status': 200, 'code': code, 'data': {}, 'msg': code_get_msg(code)})
|
||||
|
||||
data = api.songs.get_songs(limit, offset, query, sort)
|
||||
|
||||
if not data:
|
||||
return jsonify({'status': 200, 'code': -2, 'data': {}, 'msg': code_get_msg(-2)})
|
||||
|
||||
return jsonify({'status': 200, 'code': 0, 'data': data, 'msg': ''})
|
||||
58
latest version/api/songs.py
Normal file
58
latest version/api/songs.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from server.sql import Connect
|
||||
from server.sql import Sql
|
||||
import time
|
||||
|
||||
|
||||
def get_song_info(song_id):
|
||||
# 查询指定歌曲信息,返回字典
|
||||
r = {}
|
||||
|
||||
with Connect('./database/arcsong.db') as c:
|
||||
c.execute('''select * from songs where sid=:a''', {'a': song_id})
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
r = {'song_id': x[0],
|
||||
'name': {'name_en': x[1],
|
||||
'name_jp': x[2]},
|
||||
'pakset': x[5],
|
||||
'artist': x[6],
|
||||
'date': x[9],
|
||||
'rating_pst': x[13]/10,
|
||||
'rating_prs': x[14]/10,
|
||||
'rating_ftr': x[15]/10,
|
||||
'rating_byn': x[16]/10,
|
||||
'difficultly_pst': x[17]/2,
|
||||
'difficultly_prs': x[18]/2,
|
||||
'difficultly_ftr': x[19]/2,
|
||||
'difficultly_byn': x[20]/2
|
||||
}
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def get_songs(limit=-1, offset=0, query={}, sort=[]):
|
||||
# 查询全部歌曲信息,返回字典列表
|
||||
r = []
|
||||
|
||||
with Connect('./database/arcsong.db') as c:
|
||||
x = Sql.select(c, 'songs', [], limit, offset, query, sort)
|
||||
|
||||
if x:
|
||||
for i in x:
|
||||
r.append({'sid': i[0],
|
||||
'name': {'name_en': i[1],
|
||||
'name_jp': i[2]},
|
||||
'pakset': i[5],
|
||||
'artist': i[6],
|
||||
'date': i[9],
|
||||
'rating_pst': i[13]/10,
|
||||
'rating_prs': i[14]/10,
|
||||
'rating_ftr': i[15]/10,
|
||||
'rating_byn': i[16]/10,
|
||||
'difficultly_pst': i[17]/2,
|
||||
'difficultly_prs': i[18]/2,
|
||||
'difficultly_ftr': i[19]/2,
|
||||
'difficultly_byn': i[20]/2
|
||||
})
|
||||
|
||||
return r
|
||||
99
latest version/api/users.py
Normal file
99
latest version/api/users.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from server.sql import Connect
|
||||
from server.sql import Sql
|
||||
import time
|
||||
import web.webscore
|
||||
import server.info
|
||||
|
||||
|
||||
def get_users(limit=-1, offset=0, query={}, sort=[]):
|
||||
# 获取全用户信息,返回字典列表
|
||||
|
||||
r = []
|
||||
with Connect() as c:
|
||||
x = Sql.select(c, 'user', [], limit, offset, query, sort)
|
||||
|
||||
if x:
|
||||
for i in x:
|
||||
if i[23] != -1:
|
||||
character_id = i[23]
|
||||
else:
|
||||
character_id = i[6]
|
||||
r.append({
|
||||
'user_id': i[0],
|
||||
'name': i[1],
|
||||
'join_date': i[3],
|
||||
'user_code': i[4],
|
||||
'rating_ptt': i[5]/100,
|
||||
'character_id': character_id,
|
||||
'is_char_uncapped': i[8] == 1,
|
||||
'is_char_uncapped_override': i[9] == 1,
|
||||
'is_hide_rating': i[10],
|
||||
'ticket': i[26]
|
||||
})
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def get_user_info(user_id):
|
||||
# 获取用户信息,返回字典,其实就是调用user/me信息
|
||||
|
||||
r = {}
|
||||
with Connect() as c:
|
||||
r = server.info.get_user_me(c, user_id)
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def get_user_b30(user_id):
|
||||
# 获取用户b30信息,返回字典
|
||||
|
||||
r = []
|
||||
with Connect() as c:
|
||||
r = web.webscore.get_user_score(c, user_id, 30)
|
||||
|
||||
bestptt = 0
|
||||
for i in r:
|
||||
if i['rating']:
|
||||
bestptt += i['rating']
|
||||
if 'time_played' in i:
|
||||
i['time_played'] = int(time.mktime(time.strptime(
|
||||
i['time_played'], '%Y-%m-%d %H:%M:%S')))
|
||||
|
||||
return {'user_id': user_id, 'b30_ptt': bestptt / 30, 'data': r}
|
||||
|
||||
|
||||
def get_user_best(user_id, limit=-1, offset=0, query={}, sort=[]):
|
||||
# 获取用户b30信息,返回字典
|
||||
|
||||
r = []
|
||||
with Connect() as c:
|
||||
x = Sql.select(c, 'best_score', [], limit, offset, query, sort)
|
||||
if x:
|
||||
for i in x:
|
||||
r.append({
|
||||
"song_id": i[1],
|
||||
"difficulty": i[2],
|
||||
"score": i[3],
|
||||
"shiny_perfect_count": i[4],
|
||||
"perfect_count": i[5],
|
||||
"near_count": i[6],
|
||||
"miss_count": i[7],
|
||||
"health": i[8],
|
||||
"modifier": i[9],
|
||||
"time_played": i[10],
|
||||
"best_clear_type": i[11],
|
||||
"clear_type": i[12],
|
||||
"rating": i[13]
|
||||
})
|
||||
|
||||
return {'user_id': user_id, 'data': r}
|
||||
|
||||
|
||||
def get_user_r30(user_id):
|
||||
# 获取用户r30信息,返回字典
|
||||
|
||||
r = []
|
||||
with Connect() as c:
|
||||
r, r10_ptt = web.webscore.get_user_recent30(c, user_id)
|
||||
|
||||
return {'user_id': user_id, 'r10_ptt': r10_ptt, 'data': r}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,354 +1,511 @@
|
||||
import sqlite3
|
||||
import hashlib
|
||||
import time
|
||||
import json
|
||||
|
||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
||||
|
||||
conn = sqlite3.connect('arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''create table if not exists user(user_id int primary key,
|
||||
name text unique,
|
||||
password text not null,
|
||||
join_date char(20),
|
||||
user_code char(10),
|
||||
rating_ptt int,
|
||||
character_id int,
|
||||
is_skill_sealed int,
|
||||
is_char_uncapped int,
|
||||
is_char_uncapped_override int,
|
||||
is_hide_rating int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
score int,
|
||||
shiny_perfect_count int,
|
||||
perfect_count int,
|
||||
near_count int,
|
||||
miss_count int,
|
||||
health int,
|
||||
modifier int,
|
||||
time_played int,
|
||||
clear_type int,
|
||||
rating real,
|
||||
favorite_character int,
|
||||
max_stamina_notification_enabled int,
|
||||
current_map text,
|
||||
ticket int
|
||||
);''')
|
||||
c.execute('''create table if not exists login(access_token text,
|
||||
user_id int primary key,
|
||||
last_login_time int,
|
||||
last_login_ip text,
|
||||
last_login_device text
|
||||
);''')
|
||||
c.execute('''create table if not exists friend(user_id_me int,
|
||||
user_id_other int,
|
||||
primary key (user_id_me, user_id_other)
|
||||
);''')
|
||||
c.execute('''create table if not exists best_score(user_id int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
score int,
|
||||
shiny_perfect_count int,
|
||||
perfect_count int,
|
||||
near_count int,
|
||||
miss_count int,
|
||||
health int,
|
||||
modifier int,
|
||||
time_played int,
|
||||
best_clear_type int,
|
||||
clear_type int,
|
||||
rating real,
|
||||
primary key(user_id, song_id, difficulty)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_char(user_id int,
|
||||
character_id int,
|
||||
level int,
|
||||
exp real,
|
||||
level_exp real,
|
||||
frag real,
|
||||
prog real,
|
||||
overdrive real,
|
||||
skill_id text,
|
||||
skill_unlock_level int,
|
||||
skill_requires_uncap int,
|
||||
skill_id_uncap text,
|
||||
char_type int,
|
||||
is_uncapped int,
|
||||
is_uncapped_override int,
|
||||
primary key(user_id, character_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists character(character_id int primary key,
|
||||
name text,
|
||||
level int,
|
||||
exp real,
|
||||
level_exp real,
|
||||
frag real,
|
||||
prog real,
|
||||
overdrive real,
|
||||
skill_id text,
|
||||
skill_unlock_level int,
|
||||
skill_requires_uncap int,
|
||||
skill_id_uncap text,
|
||||
char_type int,
|
||||
uncap_cores text,
|
||||
is_uncapped int,
|
||||
is_uncapped_override int
|
||||
);''')
|
||||
c.execute('''create table if not exists recent30(user_id int primary key,
|
||||
r0 real,
|
||||
song_id0 text,
|
||||
r1 real,
|
||||
song_id1 text,
|
||||
r2 real,
|
||||
song_id2 text,
|
||||
r3 real,
|
||||
song_id3 text,
|
||||
r4 real,
|
||||
song_id4 text,
|
||||
r5 real,
|
||||
song_id5 text,
|
||||
r6 real,
|
||||
song_id6 text,
|
||||
r7 real,
|
||||
song_id7 text,
|
||||
r8 real,
|
||||
song_id8 text,
|
||||
r9 real,
|
||||
song_id9 text,
|
||||
r10 real,
|
||||
song_id10 text,
|
||||
r11 real,
|
||||
song_id11 text,
|
||||
r12 real,
|
||||
song_id12 text,
|
||||
r13 real,
|
||||
song_id13 text,
|
||||
r14 real,
|
||||
song_id14 text,
|
||||
r15 real,
|
||||
song_id15 text,
|
||||
r16 real,
|
||||
song_id16 text,
|
||||
r17 real,
|
||||
song_id17 text,
|
||||
r18 real,
|
||||
song_id18 text,
|
||||
r19 real,
|
||||
song_id19 text,
|
||||
r20 real,
|
||||
song_id20 text,
|
||||
r21 real,
|
||||
song_id21 text,
|
||||
r22 real,
|
||||
song_id22 text,
|
||||
r23 real,
|
||||
song_id23 text,
|
||||
r24 real,
|
||||
song_id24 text,
|
||||
r25 real,
|
||||
song_id25 text,
|
||||
r26 real,
|
||||
song_id26 text,
|
||||
r27 real,
|
||||
song_id27 text,
|
||||
r28 real,
|
||||
song_id28 text,
|
||||
r29 real,
|
||||
song_id29 text
|
||||
);''')
|
||||
c.execute('''create table if not exists user_world(user_id int,
|
||||
map_id text,
|
||||
curr_position int,
|
||||
curr_capture real,
|
||||
is_locked int,
|
||||
primary key(user_id, map_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists world_songplay(user_id int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
stamina_multiply int,
|
||||
fragment_multiply int,
|
||||
prog_boost_multiply int,
|
||||
primary key(user_id, song_id, difficulty)
|
||||
);''')
|
||||
c.execute('''create table if not exists download_token(user_id int,
|
||||
song_id text,
|
||||
file_name text,
|
||||
token text,
|
||||
time int,
|
||||
primary key(user_id, song_id, file_name)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_download(user_id int,
|
||||
token text,
|
||||
time int,
|
||||
primary key(user_id, token, time)
|
||||
);''')
|
||||
c.execute('''create table if not exists item(item_id text,
|
||||
type text,
|
||||
is_available int,
|
||||
price int,
|
||||
orig_price int,
|
||||
discount_from int,
|
||||
discount_to int,
|
||||
_id text,
|
||||
primary key(item_id, type)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_item(user_id int,
|
||||
item_id text,
|
||||
type text,
|
||||
primary key(user_id, item_id, type)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_save(user_id int primary key,
|
||||
scores_data text,
|
||||
clearlamps_data text,
|
||||
clearedsongs_data text,
|
||||
unlocklist_data text,
|
||||
installid_data text,
|
||||
devicemodelname_data text,
|
||||
story_data text,
|
||||
createdAt int
|
||||
);''')
|
||||
c.execute('''create table if not exists present(present_id text primary key,
|
||||
expire_ts int,
|
||||
items text,
|
||||
description text
|
||||
);''')
|
||||
c.execute('''create table if not exists user_present(user_id int,
|
||||
present_id text,
|
||||
primary key(user_id, present_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists songfile(song_id text,
|
||||
file_type int,
|
||||
md5 text,
|
||||
primary key(song_id, file_type)
|
||||
);''')
|
||||
c.execute('''create table if not exists redeem(code text primary key,
|
||||
items text,
|
||||
type int
|
||||
);''')
|
||||
c.execute('''create table if not exists user_redeem(user_id int,
|
||||
code text,
|
||||
primary key(user_id, code)
|
||||
);''')
|
||||
ARCAEA_SERVER_VERSION = 'v2.6.1'
|
||||
|
||||
|
||||
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']
|
||||
|
||||
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']
|
||||
|
||||
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee',
|
||||
'', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
|
||||
|
||||
for i in range(0, 41):
|
||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
||||
sql = 'insert into character values('+str(
|
||||
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',1,1)'''
|
||||
c.execute(sql)
|
||||
else:
|
||||
if i != 5:
|
||||
sql = 'insert into character values('+str(
|
||||
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',0,0)'''
|
||||
c.execute(sql)
|
||||
|
||||
|
||||
def b2int(x):
|
||||
# int与布尔值转换
|
||||
if x:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def insert_items(c, items):
|
||||
# 物品数据导入
|
||||
for i in items:
|
||||
if 'discount_from' not in i:
|
||||
discount_from = -1
|
||||
else:
|
||||
discount_from = i['discount_from']
|
||||
if 'discount_to' not in i:
|
||||
discount_to = -1
|
||||
else:
|
||||
discount_to = i['discount_to']
|
||||
for j in i['items']:
|
||||
if "_id" not in j:
|
||||
_id = ''
|
||||
else:
|
||||
_id = j['_id']
|
||||
if j['type'] != 'character':
|
||||
c.execute('''insert into item(item_id, type, is_available, price, orig_price, discount_from, discount_to, _id) values(:a,:b,:c,:d,:e,:f,:g,:h)''', {
|
||||
'a': j['id'], 'b': j['type'], 'c': b2int(j['is_available']), 'd': i['price'], 'e': i['orig_price'], 'f': discount_from, 'g': discount_to, 'h': _id})
|
||||
|
||||
|
||||
f = open('singles.json', 'r')
|
||||
singles = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, singles)
|
||||
|
||||
f = open('packs.json', 'r')
|
||||
packs = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, packs)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def arc_register(name: str, password: str):
|
||||
def build_user_code(c):
|
||||
return '123456789'
|
||||
|
||||
def build_user_id(c):
|
||||
return 2000000
|
||||
|
||||
# def insert_user_char(c, user_id):
|
||||
# for i in range(0, 38):
|
||||
# if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
||||
# sql = 'insert into user_char values('+str(user_id)+','+str(
|
||||
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
||||
# c.execute(sql)
|
||||
# else:
|
||||
# if i != 5:
|
||||
# sql = 'insert into user_char values('+str(user_id)+','+str(
|
||||
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
||||
# c.execute(sql)
|
||||
def insert_user_char(c, user_id):
|
||||
# 为用户添加所有可用角色
|
||||
c.execute('''select * from character''')
|
||||
x = c.fetchall()
|
||||
if x != []:
|
||||
for i in x:
|
||||
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
||||
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
||||
|
||||
conn = sqlite3.connect('arcaea_database.db')
|
||||
def main(path='./'):
|
||||
conn = sqlite3.connect(path+'arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||
c.execute(
|
||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
||||
if c.fetchone() == (0,):
|
||||
user_code = build_user_code(c)
|
||||
user_id = build_user_id(c)
|
||||
now = int(time.time() * 1000)
|
||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket)
|
||||
values(:user_id, :name, :password, :join_date, :user_code, 1250, 1, 0, 1, 0, 0, -1, 0, '', 114514)
|
||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
||||
'user_id': user_id})
|
||||
c.execute('''create table if not exists config(id text primary key,
|
||||
value text
|
||||
);''')
|
||||
c.execute('''insert into config values("version", :a);''',
|
||||
{'a': ARCAEA_SERVER_VERSION})
|
||||
c.execute('''create table if not exists user(user_id int primary key,
|
||||
name text unique,
|
||||
password text not null,
|
||||
join_date char(20),
|
||||
user_code char(10),
|
||||
rating_ptt int,
|
||||
character_id int,
|
||||
is_skill_sealed int,
|
||||
is_char_uncapped int,
|
||||
is_char_uncapped_override int,
|
||||
is_hide_rating int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
score int,
|
||||
shiny_perfect_count int,
|
||||
perfect_count int,
|
||||
near_count int,
|
||||
miss_count int,
|
||||
health int,
|
||||
modifier int,
|
||||
time_played int,
|
||||
clear_type int,
|
||||
rating real,
|
||||
favorite_character int,
|
||||
max_stamina_notification_enabled int,
|
||||
current_map text,
|
||||
ticket int,
|
||||
prog_boost int,
|
||||
email text,
|
||||
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,
|
||||
user_id int,
|
||||
login_time int,
|
||||
login_ip text,
|
||||
login_device text,
|
||||
primary key(access_token, user_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists friend(user_id_me int,
|
||||
user_id_other int,
|
||||
primary key (user_id_me, user_id_other)
|
||||
);''')
|
||||
c.execute('''create table if not exists best_score(user_id int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
score int,
|
||||
shiny_perfect_count int,
|
||||
perfect_count int,
|
||||
near_count int,
|
||||
miss_count int,
|
||||
health int,
|
||||
modifier int,
|
||||
time_played int,
|
||||
best_clear_type int,
|
||||
clear_type int,
|
||||
rating real,
|
||||
primary key(user_id, song_id, difficulty)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_char(user_id int,
|
||||
character_id int,
|
||||
level int,
|
||||
exp real,
|
||||
is_uncapped int,
|
||||
is_uncapped_override int,
|
||||
primary key(user_id, character_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_char_full(user_id int,
|
||||
character_id int,
|
||||
level int,
|
||||
exp real,
|
||||
is_uncapped int,
|
||||
is_uncapped_override int,
|
||||
primary key(user_id, character_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists character(character_id int primary key,
|
||||
name text,
|
||||
max_level int,
|
||||
frag1 real,
|
||||
prog1 real,
|
||||
overdrive1 real,
|
||||
frag20 real,
|
||||
prog20 real,
|
||||
overdrive20 real,
|
||||
frag30 real,
|
||||
prog30 real,
|
||||
overdrive30 real,
|
||||
skill_id text,
|
||||
skill_unlock_level int,
|
||||
skill_requires_uncap int,
|
||||
skill_id_uncap text,
|
||||
char_type int,
|
||||
is_uncapped int
|
||||
);''')
|
||||
c.execute('''create table if not exists char_item(character_id int,
|
||||
item_id text,
|
||||
type text,
|
||||
amount int,
|
||||
primary key(character_id, item_id, type)
|
||||
);''')
|
||||
c.execute('''create table if not exists recent30(user_id int primary key,
|
||||
r0 real,
|
||||
song_id0 text,
|
||||
r1 real,
|
||||
song_id1 text,
|
||||
r2 real,
|
||||
song_id2 text,
|
||||
r3 real,
|
||||
song_id3 text,
|
||||
r4 real,
|
||||
song_id4 text,
|
||||
r5 real,
|
||||
song_id5 text,
|
||||
r6 real,
|
||||
song_id6 text,
|
||||
r7 real,
|
||||
song_id7 text,
|
||||
r8 real,
|
||||
song_id8 text,
|
||||
r9 real,
|
||||
song_id9 text,
|
||||
r10 real,
|
||||
song_id10 text,
|
||||
r11 real,
|
||||
song_id11 text,
|
||||
r12 real,
|
||||
song_id12 text,
|
||||
r13 real,
|
||||
song_id13 text,
|
||||
r14 real,
|
||||
song_id14 text,
|
||||
r15 real,
|
||||
song_id15 text,
|
||||
r16 real,
|
||||
song_id16 text,
|
||||
r17 real,
|
||||
song_id17 text,
|
||||
r18 real,
|
||||
song_id18 text,
|
||||
r19 real,
|
||||
song_id19 text,
|
||||
r20 real,
|
||||
song_id20 text,
|
||||
r21 real,
|
||||
song_id21 text,
|
||||
r22 real,
|
||||
song_id22 text,
|
||||
r23 real,
|
||||
song_id23 text,
|
||||
r24 real,
|
||||
song_id24 text,
|
||||
r25 real,
|
||||
song_id25 text,
|
||||
r26 real,
|
||||
song_id26 text,
|
||||
r27 real,
|
||||
song_id27 text,
|
||||
r28 real,
|
||||
song_id28 text,
|
||||
r29 real,
|
||||
song_id29 text
|
||||
);''')
|
||||
c.execute('''create table if not exists user_world(user_id int,
|
||||
map_id text,
|
||||
curr_position int,
|
||||
curr_capture real,
|
||||
is_locked int,
|
||||
primary key(user_id, map_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists world_songplay(user_id int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
stamina_multiply int,
|
||||
fragment_multiply int,
|
||||
prog_boost_multiply int,
|
||||
primary key(user_id, song_id, difficulty)
|
||||
);''')
|
||||
c.execute('''create table if not exists download_token(user_id int,
|
||||
song_id text,
|
||||
file_name text,
|
||||
token text,
|
||||
time int,
|
||||
primary key(user_id, song_id, file_name)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_download(user_id int,
|
||||
token text,
|
||||
time int,
|
||||
primary key(user_id, token, time)
|
||||
);''')
|
||||
c.execute('''create table if not exists item(item_id text,
|
||||
type text,
|
||||
is_available int,
|
||||
_id text,
|
||||
primary key(item_id, type)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_item(user_id int,
|
||||
item_id text,
|
||||
type text,
|
||||
amount int,
|
||||
primary key(user_id, item_id, type)
|
||||
);''')
|
||||
c.execute('''create table if not exists purchase(purchase_name text primary key,
|
||||
price int,
|
||||
orig_price int,
|
||||
discount_from int,
|
||||
discount_to int
|
||||
);''')
|
||||
c.execute('''create table if not exists purchase_item(purchase_name text,
|
||||
item_id text,
|
||||
type text,
|
||||
primary key(purchase_name, item_id, type)
|
||||
);''')
|
||||
c.execute('''create table if not exists user_save(user_id int primary key,
|
||||
scores_data text,
|
||||
clearlamps_data text,
|
||||
clearedsongs_data text,
|
||||
unlocklist_data text,
|
||||
installid_data text,
|
||||
devicemodelname_data text,
|
||||
story_data text,
|
||||
createdAt int
|
||||
);''')
|
||||
c.execute('''create table if not exists present(present_id text primary key,
|
||||
expire_ts int,
|
||||
description text
|
||||
);''')
|
||||
c.execute('''create table if not exists user_present(user_id int,
|
||||
present_id text,
|
||||
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,
|
||||
file_type int,
|
||||
md5 text,
|
||||
primary key(song_id, file_type)
|
||||
);''')
|
||||
c.execute('''create table if not exists redeem(code text primary key,
|
||||
type int
|
||||
);''')
|
||||
c.execute('''create table if not exists user_redeem(user_id int,
|
||||
code text,
|
||||
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,
|
||||
role_name text,
|
||||
caption text
|
||||
);''')
|
||||
c.execute('''create table if not exists user_role(user_id int,
|
||||
role_id int,
|
||||
primary key(user_id, role_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists power(power_id int primary key,
|
||||
power_name text,
|
||||
caption text
|
||||
);''')
|
||||
c.execute('''create table if not exists role_power(role_id int,
|
||||
power_id int,
|
||||
primary key(role_id, power_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists api_login(user_id int,
|
||||
token text,
|
||||
login_time int,
|
||||
login_ip text,
|
||||
primary key(user_id, token)
|
||||
);''')
|
||||
|
||||
# 搭档初始化
|
||||
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', '???', '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',
|
||||
'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',
|
||||
'', '', '', '', '', '', '', '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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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 = {
|
||||
0: [{'core_id': 'core_hollow', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}],
|
||||
1: [{'core_id': 'core_hollow', 'amount': 5}, {'core_id': 'core_desolate', 'amount': 25}],
|
||||
2: [{'core_id': 'core_hollow', 'amount': 5}, {'core_id': 'core_crimson', 'amount': 25}],
|
||||
4: [{'core_id': 'core_ambivalent', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}],
|
||||
13: [{'core_id': 'core_scarlet', 'amount': 30}],
|
||||
21: [{'core_id': 'core_scarlet', 'amount': 30}],
|
||||
26: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||
27: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||
28: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||
29: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||
36: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||
42: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||
43: [{'core_id': 'core_chunithm', 'amount': 15}]
|
||||
}
|
||||
|
||||
for i in range(0, 48):
|
||||
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]:
|
||||
sql = '''insert into character values(?,?,30,?,?,?,?,?,?,?,?,?,?,?,?,?,?,1)'''
|
||||
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]))
|
||||
else:
|
||||
if i != 5 and i != 46:
|
||||
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],
|
||||
frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i]))
|
||||
|
||||
for i in char_core:
|
||||
for j in char_core[i]:
|
||||
c.execute('''insert into char_item values(?,?,'core',?)''',
|
||||
(i, j['core_id'], j['amount']))
|
||||
cores = ['core_hollow', 'core_desolate', 'core_chunithm', 'core_crimson',
|
||||
'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic']
|
||||
|
||||
for i in cores:
|
||||
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",
|
||||
"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"]
|
||||
for i in world_songs:
|
||||
c.execute('''insert into item values(?,"world_song",1,'')''', (i,))
|
||||
|
||||
world_unlocks = ["scenery_chap1", "scenery_chap2",
|
||||
"scenery_chap3", "scenery_chap4", "scenery_chap5"]
|
||||
for i in world_unlocks:
|
||||
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):
|
||||
# 物品数据导入
|
||||
for i in items:
|
||||
if 'discount_from' not in i:
|
||||
discount_from = -1
|
||||
else:
|
||||
discount_from = i['discount_from']
|
||||
if 'discount_to' not in i:
|
||||
discount_to = -1
|
||||
else:
|
||||
discount_to = i['discount_to']
|
||||
c.execute('''insert into purchase values(?,?,?,?,?)''',
|
||||
(i['name'], i['price'], i['orig_price'], discount_from, discount_to))
|
||||
for j in i['items']:
|
||||
if "_id" not in j:
|
||||
_id = ''
|
||||
else:
|
||||
_id = j['_id']
|
||||
c.execute('''insert into item values(?,?,?,?)''',
|
||||
(j['id'], j['type'], j['is_available'], _id))
|
||||
c.execute('''insert into purchase_item values(?,?,?)''',
|
||||
(i['name'], j['id'], j['type']))
|
||||
|
||||
# item初始化
|
||||
f = open(path+'singles.json', 'r')
|
||||
singles = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, singles)
|
||||
|
||||
f = open(path+'packs.json', 'r')
|
||||
packs = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, packs)
|
||||
|
||||
# api权限与权限组初始化
|
||||
role = ['admin', 'user', 'selecter']
|
||||
role_caption = ['管理员', '用户', '查询接口']
|
||||
|
||||
power = ['select', 'select_me', 'change', 'change_me', 'grant',
|
||||
'grant_inf', 'select_song_rank', 'select_song_info']
|
||||
power_caption = ['总体查询权限', '自我查询权限', '总体修改权限',
|
||||
'自我修改权限', '授权权限', '下级授权权限', '歌曲排行榜查询权限', '歌曲信息查询权限']
|
||||
|
||||
role_power = {'0': [0, 1, 3, 5, 6, 7],
|
||||
'1': [1, 3, 6, 7],
|
||||
'2': [0]
|
||||
}
|
||||
|
||||
for i in range(0, len(role)):
|
||||
c.execute('''insert into role values(:a,:b,:c)''', {
|
||||
'a': i, 'b': role[i], 'c': role_caption[i]})
|
||||
for i in range(0, len(power)):
|
||||
c.execute('''insert into power values(:a,:b,:c)''', {
|
||||
'a': i, 'b': power[i], 'c': power_caption[i]})
|
||||
for i in role_power:
|
||||
for j in role_power[i]:
|
||||
c.execute('''insert into role_power values(:a,:b)''',
|
||||
{'a': int(i), 'b': j})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def arc_register(name: str):
|
||||
def build_user_code(c):
|
||||
return '123456789'
|
||||
|
||||
def build_user_id(c):
|
||||
return 2000000
|
||||
|
||||
def insert_user_char(c, user_id):
|
||||
# 为用户添加可用角色
|
||||
c.execute('''insert into user_char values(?,?,?,?,?,?)''',
|
||||
(user_id, 0, 30, 25000, 1, 0))
|
||||
c.execute('''insert into user_char values(?,?,?,?,?,?)''',
|
||||
(user_id, 1, 30, 25000, 1, 0))
|
||||
|
||||
c.execute(
|
||||
'''select character_id, max_level, is_uncapped from character''')
|
||||
x = c.fetchall()
|
||||
if x:
|
||||
for i in x:
|
||||
exp = 25000 if i[1] == 30 else 10000
|
||||
c.execute('''insert into user_char_full values(?,?,?,?,?,?)''',
|
||||
(user_id, i[0], i[1], exp, i[2], 0))
|
||||
|
||||
conn = sqlite3.connect(path+'arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
hash_pwd = '41e5653fc7aeb894026d6bb7b2db7f65902b454945fa8fd65a6327047b5277fb'
|
||||
c.execute(
|
||||
'''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200,3,3,10.8)''')
|
||||
insert_user_char(c, user_id)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
else:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
||||
if c.fetchone() == (0,):
|
||||
user_code = build_user_code(c)
|
||||
user_id = build_user_id(c)
|
||||
now = int(time.time() * 1000)
|
||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket)
|
||||
values(:user_id, :name, :password, :join_date, :user_code, 1250, 1, 0, 1, 0, 0, -1, 0, '', 114514)
|
||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
||||
'user_id': user_id})
|
||||
c.execute(
|
||||
'''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200,3,3,10.8)''')
|
||||
insert_user_char(c, user_id)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
else:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
|
||||
arc_register('admin')
|
||||
|
||||
|
||||
arc_register('admin', 'admin123')
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
78
latest version/database/map/byd_lostcivilization.json
Normal file
78
latest version/database/map/byd_lostcivilization.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"map_id": "byd_lostcivilization",
|
||||
"is_legacy": false,
|
||||
"chapter": 1001,
|
||||
"available_from": -1,
|
||||
"available_to": 9999999999999,
|
||||
"is_repeatable": false,
|
||||
"require_id": "lostcivilization2",
|
||||
"require_type": "chart_unlock",
|
||||
"coordinate": "-650,-900",
|
||||
"is_beyond": true,
|
||||
"stamina_cost": 3,
|
||||
"beyond_health": 250,
|
||||
"character_affinity": [0, 1],
|
||||
"affinity_multiplier": [1.9, 1.9],
|
||||
"step_count": 7,
|
||||
"custom_bg": "",
|
||||
"curr_position": 0,
|
||||
"curr_capture": 0,
|
||||
"is_locked": false,
|
||||
"steps": [{
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 0,
|
||||
"capture": 85
|
||||
}, {
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 1,
|
||||
"capture": 5,
|
||||
"items": [{
|
||||
"type": "core",
|
||||
"id": "core_generic",
|
||||
"amount": 1
|
||||
}]
|
||||
}, {
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 2,
|
||||
"capture": 5,
|
||||
"items": [{
|
||||
"type": "core",
|
||||
"id": "core_generic",
|
||||
"amount": 1
|
||||
}]
|
||||
}, {
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 3,
|
||||
"capture": 5,
|
||||
"items": [{
|
||||
"type": "core",
|
||||
"id": "core_generic",
|
||||
"amount": 1
|
||||
}]
|
||||
}, {
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 4,
|
||||
"capture": 100,
|
||||
"items": [{
|
||||
"type": "core",
|
||||
"id": "core_generic",
|
||||
"amount": 1
|
||||
}]
|
||||
}, {
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 5,
|
||||
"capture": 50,
|
||||
"items": [{
|
||||
"type": "fragment",
|
||||
"amount": 525
|
||||
}]
|
||||
}, {
|
||||
"map_id": "byd_lostcivilization",
|
||||
"position": 6,
|
||||
"capture": 0,
|
||||
"items": [{
|
||||
"id": "lostcivilization3",
|
||||
"type": "world_song"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
114
latest version/database/map/test3.json
Normal file
114
latest version/database/map/test3.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"map_id": "test3",
|
||||
"is_legacy": true,
|
||||
"is_beyond": false,
|
||||
"beyond_health": 100,
|
||||
"character_affinity": [],
|
||||
"affinity_multiplier": [],
|
||||
"chapter": 0,
|
||||
"available_from": -1,
|
||||
"available_to": 2106124800000,
|
||||
"is_repeatable": false,
|
||||
"require_id": "",
|
||||
"require_type": "",
|
||||
"require_value": 0,
|
||||
"coordinate": "300,200",
|
||||
"step_count": 12,
|
||||
"custom_bg": "",
|
||||
"stamina_cost": 1,
|
||||
"curr_position": 0,
|
||||
"curr_capture": 0,
|
||||
"is_locked": false,
|
||||
"steps": [{
|
||||
"position": 0,
|
||||
"capture": 10
|
||||
}, {
|
||||
"position": 1,
|
||||
"capture": 10,
|
||||
"items": [{
|
||||
"type": "fragment",
|
||||
"amount": 1000
|
||||
}]
|
||||
}, {
|
||||
"position": 2,
|
||||
"capture": 10,
|
||||
"restrict_id": "base",
|
||||
"restrict_type": "pack_id",
|
||||
"items": [{
|
||||
"type": "memory",
|
||||
"amount": 150
|
||||
}]
|
||||
}, {
|
||||
"position": 3,
|
||||
"capture": 10,
|
||||
"restrict_id": "base",
|
||||
"restrict_type": "pack_id",
|
||||
"step_type": ["randomsong"],
|
||||
"items": [{
|
||||
"id": "supernova",
|
||||
"type": "world_song"
|
||||
}]
|
||||
}, {
|
||||
"position": 4,
|
||||
"capture": 10,
|
||||
"items": [{
|
||||
"type": "core",
|
||||
"id": "core_generic",
|
||||
"amount": 1
|
||||
}]
|
||||
}, {
|
||||
"position": 5,
|
||||
"capture": 10,
|
||||
"step_type": ["speedlimit"],
|
||||
"speed_limit_value": 60,
|
||||
"items": [{
|
||||
"id": "scenery_chap4",
|
||||
"type": "world_unlock"
|
||||
}]
|
||||
}, {
|
||||
"position": 6,
|
||||
"capture": 10,
|
||||
"items": [{
|
||||
"type": "fragment",
|
||||
"amount": 1250
|
||||
}]
|
||||
}, {
|
||||
"position": 7,
|
||||
"capture": 10,
|
||||
"step_type": ["plusstamina"],
|
||||
"plus_stamina_value": 2,
|
||||
"items": [{
|
||||
"type": "fragment",
|
||||
"amount": 125
|
||||
}]
|
||||
}, {
|
||||
"position": 8,
|
||||
"capture": 10,
|
||||
"items": [{
|
||||
"type": "fragment",
|
||||
"amount": 125
|
||||
}]
|
||||
}, {
|
||||
"position": 9,
|
||||
"capture": 10,
|
||||
"items": [{
|
||||
"type": "memory",
|
||||
"amount": 150
|
||||
}]
|
||||
}, {
|
||||
"position": 10,
|
||||
"capture": 10,
|
||||
"items": [{"id": "2", "type": "character"}]
|
||||
}, {
|
||||
"position": 11,
|
||||
"capture": 0,
|
||||
"items": [{
|
||||
"type": "core",
|
||||
"id": "core_crimson",
|
||||
"amount": 50
|
||||
}, {
|
||||
"type": "fragment",
|
||||
"amount": 125
|
||||
}]
|
||||
}]
|
||||
}
|
||||
@@ -3,154 +3,139 @@
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "core",
|
||||
"_id": "5ff79fc6a6e343038b058bd3",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "shiawase",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "shiawase",
|
||||
"_id": "5ff79fc6a6e343038b058c18",
|
||||
"is_available": true
|
||||
}, {
|
||||
"type": "character",
|
||||
"id": "kou",
|
||||
"_id": "5ff79fc6a6e343038b058c17",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1552089600000,
|
||||
"discount_to": 1552694399000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "dynamix",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "dynamix",
|
||||
"_id": "5ff79fc6a6e343038b058c1c",
|
||||
"is_available": true
|
||||
}, {
|
||||
"type": "character",
|
||||
"id": "sapphire",
|
||||
"_id": "5ff79fc6a6e343038b058c1b",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "mirai",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "mirai",
|
||||
"_id": "5ff79fc6a6e343038b058c10",
|
||||
"is_available": true
|
||||
}, {
|
||||
"type": "character",
|
||||
"id": "lethe",
|
||||
"_id": "5ff79fc6a6e343038b058c0f",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1552089600000,
|
||||
"discount_to": 1552694399000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "yugamu",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "yugamu",
|
||||
"_id": "5ff79fc6a6e343038b058bd4",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "lanota",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "lanota",
|
||||
"_id": "5ff79fc6a6e343038b058bf9",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "nijuusei",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "nijuusei",
|
||||
"_id": "5ff79fc6a6e343038b058bd5",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "rei",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "rei",
|
||||
"_id": "5ff79fc6a6e343038b058c06",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "tonesphere",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "tonesphere",
|
||||
"_id": "5ff79fc6a6e343038b058bfb",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "groovecoaster",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "groovecoaster",
|
||||
"_id": "5ff79fc6a6e343038b058bf0",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "zettai",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "zettai",
|
||||
"_id": "5ff79fc6a6e343038b058c08",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1583712000000,
|
||||
"discount_to": 1584316799000
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "chunithm",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "chunithm",
|
||||
"_id": "5ff79fc6a6e343038b058be4",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 300,
|
||||
@@ -160,47 +145,50 @@
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "prelude",
|
||||
"_id": "5ff79fc6a6e343038b058bf1",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 400,
|
||||
"orig_price": 400
|
||||
"orig_price": 400,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "omatsuri",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "omatsuri",
|
||||
"_id": "5ff79fc6a6e343038b058c09",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "vs",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "vs",
|
||||
"_id": "5ff79fc6a6e343038b058be7",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 500,
|
||||
"orig_price": 500
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "extend",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "extend",
|
||||
"_id": "5ff79fc6a6e343038b058bf4",
|
||||
"is_available": true
|
||||
}],
|
||||
"price": 700,
|
||||
"orig_price": 700
|
||||
"orig_price": 700,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
}, {
|
||||
"name": "alice",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "alice",
|
||||
"_id": "5ff79fc6a6e343038b058c0e",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 500,
|
||||
@@ -210,7 +198,6 @@
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "alice_append_1",
|
||||
"_id": "5ff79fc6a6e343038b058bde",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 300,
|
||||
@@ -220,7 +207,6 @@
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "ongeki",
|
||||
"_id": "5ff79fc6a6e343038b058bea",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 400,
|
||||
@@ -230,9 +216,44 @@
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "maimai",
|
||||
"_id": "5ff79fc6a6e343038b058bf7",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 400,
|
||||
"price": 400
|
||||
}, {
|
||||
"name": "chunithm_append_1",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "chunithm_append_1",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
}, {
|
||||
"name": "observer_append_1",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "observer_append_1",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
}, {
|
||||
"name": "observer",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "observer",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 500,
|
||||
"price": 500
|
||||
}, {
|
||||
"name": "observer_append_2",
|
||||
"items": [{
|
||||
"type": "pack",
|
||||
"id": "observer_append_2",
|
||||
"is_available": true
|
||||
}],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
}]
|
||||
File diff suppressed because it is too large
Load Diff
0
latest version/log/error.log
Normal file
0
latest version/log/error.log
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1 +1,2 @@
|
||||
python main.py
|
||||
cd /d %~dp0
|
||||
python -B main.py
|
||||
@@ -2,10 +2,12 @@ import os
|
||||
import hashlib
|
||||
from flask import url_for
|
||||
import sqlite3
|
||||
from server.sql import Connect
|
||||
import time
|
||||
from setting import Config
|
||||
|
||||
time_limit = 3000 # 每个玩家24小时下载次数限制
|
||||
time_gap_limit = 1000 # 下载链接有效秒数
|
||||
time_limit = Config.DOWNLOAD_TIMES_LIMIT # 每个玩家24小时下载次数限制
|
||||
time_gap_limit = Config.DOWNLOAD_TIME_GAP_LIMIT # 下载链接有效秒数
|
||||
|
||||
|
||||
def get_file_md5(file_path):
|
||||
@@ -13,17 +15,34 @@ def get_file_md5(file_path):
|
||||
if not os.path.isfile(file_path):
|
||||
return None
|
||||
myhash = hashlib.md5()
|
||||
f = open(file_path, 'rb')
|
||||
while True:
|
||||
b = f.read(8096)
|
||||
if not b:
|
||||
break
|
||||
myhash.update(b)
|
||||
f.close()
|
||||
with open(file_path, 'rb') as f:
|
||||
while True:
|
||||
b = f.read(8096)
|
||||
if not b:
|
||||
break
|
||||
myhash.update(b)
|
||||
|
||||
return myhash.hexdigest()
|
||||
|
||||
|
||||
def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
|
||||
def get_url(file_path, **kwargs):
|
||||
# 获取下载地址
|
||||
|
||||
t = ''
|
||||
if 't' in kwargs:
|
||||
t = kwargs['t']
|
||||
|
||||
if Config.DOWNLOAD_LINK_PREFIX:
|
||||
prefix = Config.DOWNLOAD_LINK_PREFIX
|
||||
if prefix[-1] != '/':
|
||||
prefix += '/'
|
||||
|
||||
return prefix + file_path + '?t=' + t
|
||||
else:
|
||||
return url_for('download', file_path=file_path, t=t, _external=True)
|
||||
|
||||
|
||||
def get_one_song(c, user_id, song_id, file_dir='./database/songs', url_flag=True):
|
||||
# 获取一首歌的下载链接,返回字典
|
||||
dir_list = os.listdir(os.path.join(file_dir, song_id))
|
||||
re = {}
|
||||
@@ -35,7 +54,6 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
|
||||
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']:
|
||||
token = hashlib.md5(
|
||||
(str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest()
|
||||
token = token[:8]
|
||||
|
||||
if i == 'base.ogg':
|
||||
c.execute(
|
||||
@@ -46,8 +64,12 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
|
||||
else:
|
||||
checksum = get_file_md5(os.path.join(
|
||||
file_dir, song_id, 'base.ogg'))
|
||||
re['audio'] = {"checksum": checksum,
|
||||
"url": url_for('download', file_path=song_id+'/base.ogg', t=token, _external=True)}
|
||||
|
||||
if url_flag:
|
||||
re['audio'] = {"checksum": checksum, "url": get_url(
|
||||
file_path=song_id+'/base.ogg', t=token)}
|
||||
else:
|
||||
re['audio'] = {"checksum": checksum}
|
||||
else:
|
||||
if 'chart' not in re:
|
||||
re['chart'] = {}
|
||||
@@ -58,87 +80,81 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
|
||||
checksum = x[0]
|
||||
else:
|
||||
checksum = get_file_md5(os.path.join(file_dir, song_id, i))
|
||||
re['chart'][i[0]] = {"checksum": checksum,
|
||||
"url": url_for('download', file_path=song_id+'/'+i, t=token, _external=True)}
|
||||
|
||||
c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', {
|
||||
'a': user_id, 'b': song_id, 'c': i, 'd': token, 'e': now})
|
||||
if url_flag:
|
||||
re['chart'][i[0]] = {"checksum": checksum, "url": get_url(
|
||||
file_path=song_id+'/'+i, t=token)}
|
||||
else:
|
||||
re['chart'][i[0]] = {"checksum": checksum}
|
||||
|
||||
if url_flag:
|
||||
c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', {
|
||||
'a': user_id, 'b': song_id, 'c': i, 'd': token, 'e': now})
|
||||
|
||||
return {song_id: re}
|
||||
|
||||
|
||||
def get_all_songs(user_id, file_dir='./database/songs'):
|
||||
def get_all_songs(user_id, file_dir='./database/songs', url_flag=True):
|
||||
# 获取所有歌的下载链接,返回字典
|
||||
dir_list = os.listdir(file_dir)
|
||||
re = {}
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
for i in dir_list:
|
||||
if os.path.isdir(os.path.join(file_dir, i)):
|
||||
re.update(get_one_song(c, user_id, i, file_dir))
|
||||
with Connect() as c:
|
||||
for i in dir_list:
|
||||
if os.path.isdir(os.path.join(file_dir, i)):
|
||||
re.update(get_one_song(c, user_id, i, file_dir, url_flag))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return re
|
||||
|
||||
|
||||
def get_some_songs(user_id, song_ids):
|
||||
# 获取一些歌的下载链接,返回字典
|
||||
re = {}
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
for song_id in song_ids:
|
||||
re.update(get_one_song(c, user_id, song_id))
|
||||
with Connect() as c:
|
||||
for song_id in song_ids:
|
||||
re.update(get_one_song(c, user_id, song_id))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return re
|
||||
|
||||
|
||||
def is_token_able_download(t):
|
||||
# token是否可以下载,返回错误码,0即可以
|
||||
errorcode = 0
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select * from download_token where token = :t limit 1''',
|
||||
{'t': t})
|
||||
x = c.fetchone()
|
||||
now = int(time.time())
|
||||
if x and now - x[4] <= time_gap_limit:
|
||||
c.execute(
|
||||
'''select count(*) from user_download where user_id = :a''', {'a': x[0]})
|
||||
y = c.fetchone()
|
||||
if y and y[0] <= time_limit:
|
||||
c.execute('''insert into user_download values(:a,:b,:c)''', {
|
||||
'a': x[0], 'b': x[3], 'c': now})
|
||||
errorcode = 108
|
||||
with Connect() as c:
|
||||
c.execute('''select * from download_token where token = :t limit 1''',
|
||||
{'t': t})
|
||||
x = c.fetchone()
|
||||
now = int(time.time())
|
||||
if x and now - x[4] <= time_gap_limit:
|
||||
c.execute(
|
||||
'''select count(*) from user_download where user_id = :a''', {'a': x[0]})
|
||||
y = c.fetchone()
|
||||
if y and y[0] <= time_limit:
|
||||
c.execute('''insert into user_download values(:a,:b,:c)''', {
|
||||
'a': x[0], 'b': x[3], 'c': now})
|
||||
errorcode = 0
|
||||
else:
|
||||
errorcode = 903
|
||||
else:
|
||||
errorcode = 903
|
||||
else:
|
||||
errorcode = 108
|
||||
errorcode = 108
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return errorcode
|
||||
|
||||
|
||||
def is_able_download(user_id):
|
||||
# 是否可以下载,返回布尔值
|
||||
f = True
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
now = int(time.time())
|
||||
c.execute(
|
||||
'''delete from user_download where user_id = :a and time <= :b''', {'a': user_id, 'b': now - 24*3600})
|
||||
c.execute(
|
||||
'''select count(*) from user_download where user_id = :a''', {'a': user_id})
|
||||
y = c.fetchone()
|
||||
if y and y[0] <= time_limit:
|
||||
pass
|
||||
else:
|
||||
f = False
|
||||
f = False
|
||||
with Connect() as c:
|
||||
now = int(time.time())
|
||||
c.execute(
|
||||
'''delete from user_download where user_id = :a and time <= :b''', {'a': user_id, 'b': now - 24*3600})
|
||||
c.execute(
|
||||
'''select count(*) from user_download where user_id = :a''', {'a': user_id})
|
||||
y = c.fetchone()
|
||||
if y and y[0] <= time_limit:
|
||||
f = True
|
||||
else:
|
||||
f = False
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return f
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import sqlite3
|
||||
from server.sql import Connect
|
||||
import server.item
|
||||
import server.character
|
||||
import time
|
||||
import json
|
||||
|
||||
@@ -11,28 +13,37 @@ def int2b(x):
|
||||
return True
|
||||
|
||||
|
||||
def get_item(c, type='pack'):
|
||||
def get_purchase(c, type='pack'):
|
||||
# 读取packs内容,返回字典列表
|
||||
c.execute('''select * from item where type = :a''', {'a': type})
|
||||
c.execute(
|
||||
'''select * from purchase where purchase_name in (select purchase_name from purchase_item where type = :a)''', {'a': type})
|
||||
x = c.fetchall()
|
||||
if not x:
|
||||
return []
|
||||
|
||||
re = []
|
||||
for i in x:
|
||||
r = {"name": i[0],
|
||||
"items": [{
|
||||
"type": i[1],
|
||||
"id": i[0],
|
||||
"is_available": int2b(i[2])
|
||||
}],
|
||||
"price": i[3],
|
||||
"orig_price": i[4]}
|
||||
items = []
|
||||
c.execute(
|
||||
'''select a.* from item a, purchase_item b where a.item_id=b.item_id and a.type=b.type and b.purchase_name=:name''', {'name': i[0]})
|
||||
y = c.fetchall()
|
||||
if y:
|
||||
for j in y:
|
||||
items.append({
|
||||
"type": j[1],
|
||||
"id": j[0],
|
||||
"is_available": int2b(j[2])
|
||||
})
|
||||
|
||||
if i[5] > 0:
|
||||
r['discount_from'] = i[5]
|
||||
if i[6] > 0:
|
||||
r['discount_to'] = i[6]
|
||||
r = {"name": i[0],
|
||||
"items": items,
|
||||
"price": i[1],
|
||||
"orig_price": i[2]}
|
||||
|
||||
if i[3] > 0:
|
||||
r['discount_from'] = i[3]
|
||||
if i[4] > 0:
|
||||
r['discount_to'] = i[4]
|
||||
|
||||
re.append(r)
|
||||
|
||||
@@ -41,26 +52,17 @@ def get_item(c, type='pack'):
|
||||
|
||||
def get_single_purchase():
|
||||
# main里面没开数据库,这里写一下代替
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
re = get_item(c, type='single')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
re = []
|
||||
with Connect() as c:
|
||||
re = get_purchase(c, type='single')
|
||||
|
||||
return re
|
||||
|
||||
|
||||
def buy_pack(user_id, pack_id):
|
||||
# 曲包购买,返回字典
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select price from item where item_id = :a''', {'a': pack_id})
|
||||
price = c.fetchone()
|
||||
if price:
|
||||
price = price[0]
|
||||
else:
|
||||
price = 0
|
||||
|
||||
c.execute('''select ticket from user where user_id = :a''', {'a': user_id})
|
||||
def buy_item(c, user_id, price):
|
||||
# 购买接口,返回成功与否标识符和剩余源点数
|
||||
c.execute('''select ticket from user where user_id = :a''',
|
||||
{'a': user_id})
|
||||
ticket = c.fetchone()
|
||||
if ticket:
|
||||
ticket = ticket[0]
|
||||
@@ -68,62 +70,91 @@ def buy_pack(user_id, pack_id):
|
||||
ticket = 0
|
||||
|
||||
if ticket < price:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return {
|
||||
"success": False
|
||||
}
|
||||
return False, ticket
|
||||
|
||||
c.execute('''update user set ticket = :b where user_id = :a''',
|
||||
{'a': user_id, 'b': ticket-price})
|
||||
c.execute('''insert into user_item values(:a,:b,'pack')''',
|
||||
{'a': user_id, 'b': pack_id})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return {
|
||||
"success": True
|
||||
}
|
||||
return True, ticket - price
|
||||
|
||||
|
||||
def buy_single(user_id, single_id):
|
||||
# 单曲购买,返回字典
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select price from item where item_id = :a''',
|
||||
{'a': single_id})
|
||||
price = c.fetchone()
|
||||
if price:
|
||||
price = price[0]
|
||||
else:
|
||||
def buy_thing(user_id, purchase_id):
|
||||
# 购买物品接口,返回字典
|
||||
success_flag = False
|
||||
ticket = 0
|
||||
packs = []
|
||||
singles = []
|
||||
characters = []
|
||||
|
||||
with Connect() as c:
|
||||
c.execute('''select price, orig_price, discount_from, discount_to from purchase where purchase_name=:a''',
|
||||
{'a': purchase_id})
|
||||
x = c.fetchone()
|
||||
price = 0
|
||||
flag = False
|
||||
if x:
|
||||
price = x[0]
|
||||
orig_price = x[1]
|
||||
discount_from = x[2]
|
||||
discount_to = x[3]
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error_code": 501
|
||||
}
|
||||
|
||||
c.execute('''select ticket from user where user_id = :a''', {'a': user_id})
|
||||
ticket = c.fetchone()
|
||||
if ticket:
|
||||
ticket = ticket[0]
|
||||
else:
|
||||
ticket = 0
|
||||
c.execute(
|
||||
'''select item_id, type from purchase_item where purchase_name=:a''', {'a': purchase_id})
|
||||
x = c.fetchall()
|
||||
if x:
|
||||
now = int(time.time() * 1000)
|
||||
if not(discount_from <= now <= discount_to):
|
||||
price = orig_price
|
||||
|
||||
if ticket < price:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return {
|
||||
"success": False
|
||||
}
|
||||
flag, ticket = buy_item(c, user_id, price)
|
||||
|
||||
c.execute('''update user set ticket = :b where user_id = :a''',
|
||||
{'a': user_id, 'b': ticket-price})
|
||||
c.execute('''insert into user_item values(:a,:b,'single')''',
|
||||
{'a': user_id, 'b': single_id})
|
||||
if flag:
|
||||
for i in x:
|
||||
server.item.claim_user_item(c, user_id, i[0], i[1])
|
||||
|
||||
success_flag = True
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error_code": 501
|
||||
}
|
||||
|
||||
packs = server.item.get_user_items(c, user_id, 'pack')
|
||||
singles = server.item.get_user_items(c, user_id, 'single')
|
||||
characters = server.character.get_user_characters(c, user_id)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return {
|
||||
"success": True
|
||||
"success": success_flag,
|
||||
"value": {'user_id': user_id,
|
||||
'ticket': ticket,
|
||||
'packs': packs,
|
||||
'singles': singles,
|
||||
'characters': characters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_prog_boost(user_id):
|
||||
# 世界模式源韵强化,扣50源点,返回剩余源点数
|
||||
|
||||
ticket = -1
|
||||
with Connect() as c:
|
||||
flag, ticket = buy_item(c, user_id, 50)
|
||||
|
||||
if flag:
|
||||
c.execute('''update user set prog_boost = 1 where user_id = :a''', {
|
||||
'a': user_id})
|
||||
if ticket >= 0:
|
||||
return ticket, None
|
||||
else:
|
||||
return 0, 108
|
||||
|
||||
|
||||
def get_user_present(c, user_id):
|
||||
# 获取用户奖励,返回字典列表
|
||||
c.execute(
|
||||
@@ -134,10 +165,22 @@ def get_user_present(c, user_id):
|
||||
if x:
|
||||
for i in x:
|
||||
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],
|
||||
'description': i[3],
|
||||
'description': i[2],
|
||||
'present_id': i[0],
|
||||
'items': json.loads(i[2])
|
||||
'items': items
|
||||
})
|
||||
|
||||
return re
|
||||
@@ -146,82 +189,70 @@ def get_user_present(c, user_id):
|
||||
def claim_user_present(user_id, present_id):
|
||||
# 确认并删除用户奖励,返回成功与否的布尔值
|
||||
flag = False
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''select exists(select * from user_present where user_id=:a and present_id=:b)''',
|
||||
{'a': user_id, 'b': present_id})
|
||||
if c.fetchone() == (1,):
|
||||
flag = True
|
||||
c.execute('''delete from user_present where user_id=:a and present_id=:b''',
|
||||
with Connect() as c:
|
||||
c.execute('''select exists(select * from user_present where user_id=:a and present_id=:b)''',
|
||||
{'a': user_id, 'b': present_id})
|
||||
c.execute('''select * from present where present_id=:b''',
|
||||
{'b': present_id})
|
||||
x = c.fetchone()
|
||||
now = int(time.time() * 1000)
|
||||
if now <= int(x[1]):
|
||||
# 处理memory
|
||||
items = json.loads(x[2])
|
||||
for i in items:
|
||||
if i['id'] == 'memory':
|
||||
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})
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from user_present where user_id=:a and present_id=:b''',
|
||||
{'a': user_id, 'b': present_id})
|
||||
c.execute('''select * from present where present_id=:b''',
|
||||
{'b': present_id})
|
||||
x = c.fetchone()
|
||||
now = int(time.time() * 1000)
|
||||
if now <= int(x[1]):
|
||||
# 处理memory
|
||||
c.execute(
|
||||
'''select * from present_item where present_id=?''', (x[0],))
|
||||
y = c.fetchall()
|
||||
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:
|
||||
# 过期
|
||||
flag = False
|
||||
else:
|
||||
# 过期
|
||||
flag = False
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return flag
|
||||
|
||||
|
||||
def claim_user_redeem(user_id, code):
|
||||
# 处理兑换码,返回碎片数量和错误码
|
||||
fragment = 0
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select * from redeem where code=:a''', {'a': code})
|
||||
x = c.fetchone()
|
||||
if not x:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return 0, 504
|
||||
error_code = 108
|
||||
with Connect() as c:
|
||||
c.execute('''select * from redeem where code=:a''', {'a': code})
|
||||
x = c.fetchone()
|
||||
if not x:
|
||||
return 0, 504
|
||||
|
||||
if x[2] == 0: # 一次性
|
||||
c.execute(
|
||||
'''select exists(select * from user_redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (1,):
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return 0, 505
|
||||
elif x[2] == 1: # 每个玩家一次
|
||||
c.execute('''select exists(select * from user_redeem where code=:a and user_id=:b)''',
|
||||
if x[1] == 0: # 一次性
|
||||
c.execute(
|
||||
'''select exists(select * from user_redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (1,):
|
||||
return 0, 505
|
||||
elif x[1] == 1: # 每个玩家一次
|
||||
c.execute('''select exists(select * from user_redeem where code=:a and user_id=:b)''',
|
||||
{'a': code, 'b': user_id})
|
||||
if c.fetchone() == (1,):
|
||||
return 0, 506
|
||||
|
||||
c.execute('''insert into user_redeem values(:b,:a)''',
|
||||
{'a': code, 'b': user_id})
|
||||
if c.fetchone() == (1,):
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return 0, 506
|
||||
|
||||
c.execute('''insert into user_redeem values(:b,:a)''',
|
||||
{'a': code, 'b': user_id})
|
||||
c.execute('''select * from redeem_item where code=?''', (code,))
|
||||
x = c.fetchall()
|
||||
flag = True
|
||||
if x:
|
||||
for i in x:
|
||||
if i[2] == 'fragment':
|
||||
fragment += i[3]
|
||||
else:
|
||||
flag = flag and server.item.claim_user_item(
|
||||
c, user_id, i[1], i[2], i[3])
|
||||
if flag:
|
||||
error_code = None
|
||||
|
||||
items = json.loads(x[1])
|
||||
for i in items:
|
||||
if i['type'] == 'fragment':
|
||||
fragment = i['amount']
|
||||
if i['type'] == 'memory':
|
||||
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})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return fragment, None
|
||||
return fragment, error_code
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,12 @@
|
||||
import json
|
||||
import sqlite3
|
||||
from server.sql import Connect
|
||||
from setting import Config
|
||||
import server.item
|
||||
import server.character
|
||||
import server.info
|
||||
import server.arcpurchase
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
def int2b(x):
|
||||
@@ -11,6 +17,23 @@ def int2b(x):
|
||||
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'):
|
||||
# 获取所有地图名称,返回列表
|
||||
L = []
|
||||
@@ -23,64 +46,17 @@ def get_world_name(file_dir='./database/map'):
|
||||
|
||||
def get_world_info(map_id):
|
||||
# 读取json文件内容,返回字典
|
||||
f = open('./database/map/'+map_id+'.json', 'r')
|
||||
world_info = json.load(f)
|
||||
f.close()
|
||||
world_info = {}
|
||||
with open('./database/map/'+map_id+'.json', 'r') as f:
|
||||
world_info = json.load(f)
|
||||
|
||||
return world_info
|
||||
|
||||
|
||||
def get_user_world_info(user_id, map_id):
|
||||
# 读取json文件内容,加上用户信息,返回字典
|
||||
info = get_world_info(map_id)
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||
{'a': map_id, 'b': user_id})
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
info['curr_position'] = x[2]
|
||||
info['curr_capture'] = x[3]
|
||||
info['is_locked'] = int2b(x[4])
|
||||
else:
|
||||
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
||||
'a': user_id, 'b': map_id})
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return info
|
||||
|
||||
|
||||
def get_current_map(user_id):
|
||||
# 得到user的当前图,返回字符串
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select current_map from user where user_id = :a''',
|
||||
{'a': user_id})
|
||||
x = c.fetchone()
|
||||
re = ''
|
||||
if x:
|
||||
re = x[0]
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return re
|
||||
|
||||
|
||||
def get_world_all(user_id):
|
||||
# 读取所有地图信息并处理,返回字典列表
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
worlds = get_world_name()
|
||||
re = []
|
||||
for map_id in worlds:
|
||||
info = get_world_info(map_id)
|
||||
steps = info['steps']
|
||||
del info['steps']
|
||||
rewards = []
|
||||
for step in steps:
|
||||
if 'items' in step:
|
||||
rewards.append(
|
||||
{'items': step['items'], 'position': step['position']})
|
||||
info['rewards'] = rewards
|
||||
with Connect() as c:
|
||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||
{'a': map_id, 'b': user_id})
|
||||
x = c.fetchone()
|
||||
@@ -89,81 +65,193 @@ def get_world_all(user_id):
|
||||
info['curr_capture'] = x[3]
|
||||
info['is_locked'] = int2b(x[4])
|
||||
else:
|
||||
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
||||
'a': user_id, 'b': map_id})
|
||||
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})
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def get_current_map(user_id):
|
||||
# 得到user的当前图,返回字符串
|
||||
re = ''
|
||||
with Connect() as c:
|
||||
c.execute('''select current_map from user where user_id = :a''',
|
||||
{'a': user_id})
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
re = x[0]
|
||||
|
||||
return re
|
||||
|
||||
|
||||
def get_world_all(user_id):
|
||||
# 读取所有地图信息并处理,返回字典列表
|
||||
re = []
|
||||
worlds = get_world_name()
|
||||
with Connect() as c:
|
||||
for map_id in worlds:
|
||||
info = get_world_info(map_id)
|
||||
steps = info['steps']
|
||||
del info['steps']
|
||||
rewards = []
|
||||
for step in steps:
|
||||
if 'items' in step:
|
||||
rewards.append(
|
||||
{'items': step['items'], 'position': step['position']})
|
||||
info['rewards'] = rewards
|
||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||
{'a': map_id, 'b': user_id})
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
info['curr_position'] = x[2]
|
||||
info['curr_capture'] = x[3]
|
||||
info['is_locked'] = int2b(x[4])
|
||||
else:
|
||||
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})
|
||||
|
||||
re.append(info)
|
||||
|
||||
return re
|
||||
|
||||
|
||||
def get_available_maps():
|
||||
# 获取当前可用图(用户设定的),返回字典列表
|
||||
re = []
|
||||
for i in Config.AVAILABLE_MAP:
|
||||
info = get_world_info(i)
|
||||
del info['steps']
|
||||
del info['is_locked']
|
||||
del info['curr_position']
|
||||
del info['curr_capture']
|
||||
re.append(info)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return re
|
||||
|
||||
|
||||
def get_user_world(user_id, map_id):
|
||||
# 获取用户图信息,返回字典
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||
{'a': map_id, 'b': user_id})
|
||||
x = c.fetchone()
|
||||
re = {
|
||||
"user_id": user_id,
|
||||
"curr_position": 0,
|
||||
"curr_capture": 0,
|
||||
"is_locked": False,
|
||||
"map_id": map_id
|
||||
}
|
||||
if x:
|
||||
re['curr_position'] = x[2]
|
||||
re['curr_capture'] = x[3]
|
||||
re['is_locked'] = int2b(x[4])
|
||||
else:
|
||||
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
||||
'a': user_id, 'b': map_id})
|
||||
re = {}
|
||||
with Connect() as c:
|
||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||
{'a': map_id, 'b': user_id})
|
||||
x = c.fetchone()
|
||||
re = {
|
||||
"user_id": user_id,
|
||||
"curr_position": 0,
|
||||
"curr_capture": 0,
|
||||
"is_locked": True,
|
||||
"map_id": map_id
|
||||
}
|
||||
if x:
|
||||
re['curr_position'] = x[2]
|
||||
re['curr_capture'] = x[3]
|
||||
re['is_locked'] = int2b(x[4])
|
||||
else:
|
||||
c.execute('''insert into user_world values(:a,:b,0,0,1)''', {
|
||||
'a': user_id, 'b': map_id})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
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):
|
||||
# 改变用户当前图
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''update user set current_map = :a where user_id=:b''', {
|
||||
'a': map_id, 'b': user_id})
|
||||
conn.commit()
|
||||
conn.close()
|
||||
with Connect() as c:
|
||||
c.execute('''update user set current_map = :a where user_id=:b''', {
|
||||
'a': map_id, 'b': user_id})
|
||||
return None
|
||||
|
||||
|
||||
def play_world_song(user_id, args):
|
||||
# 声明是世界模式的打歌,并且记录加成信息
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
# 声明是世界模式的打歌,并且记录加成信息,返回字典
|
||||
r = {}
|
||||
with Connect() as c:
|
||||
stamina_multiply = 1
|
||||
fragment_multiply = 100
|
||||
prog_boost_multiply = 0
|
||||
if 'stamina_multiply' in args:
|
||||
stamina_multiply = int(args['stamina_multiply'])
|
||||
if 'fragment_multiply' in args:
|
||||
fragment_multiply = int(args['fragment_multiply'])
|
||||
if 'prog_boost_multiply' in args:
|
||||
c.execute('''select prog_boost from user where user_id=:a''', {
|
||||
'a': user_id})
|
||||
x = c.fetchone()
|
||||
if x and x[0] == 1:
|
||||
prog_boost_multiply = 300
|
||||
|
||||
stamina_multiply = 1
|
||||
fragment_multiply = 100
|
||||
prog_boost_multiply = 0
|
||||
if 'stamina_multiply' in args:
|
||||
stamina_multiply = int(args['stamina_multiply'])
|
||||
if 'fragment_multiply' in args:
|
||||
fragment_multiply = int(args['fragment_multiply'])
|
||||
if 'prog_boost_multiply' in args:
|
||||
prog_boost_multiply = int(args['prog_boost_multiply'])
|
||||
c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||
'a': user_id, 'b': args['song_id'], 'c': args['difficulty']})
|
||||
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})
|
||||
|
||||
c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||
'a': user_id, 'b': args['song_id'], 'c': args['difficulty']})
|
||||
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})
|
||||
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)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
# 体力不足
|
||||
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):
|
||||
# 爬梯子,返回奖励列表,台阶列表,当前的位置和坐标,图信息
|
||||
|
||||
info = get_world_info(map_id)
|
||||
step_count = int(info['step_count'])
|
||||
|
||||
@@ -257,3 +345,241 @@ def climb_step(user_id, map_id, step, prev_capture, prev_position):
|
||||
steps.append(x)
|
||||
|
||||
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):
|
||||
# 成绩上传后世界模式更新,返回字典
|
||||
|
||||
step_times = stamina_multiply * fragment_multiply / \
|
||||
100 * (prog_boost_multiply+100)/100
|
||||
exp_times = stamina_multiply * (prog_boost_multiply+100)/100
|
||||
if prog_boost_multiply != 0:
|
||||
c.execute('''update user set prog_boost = 0 where user_id = :a''', {
|
||||
'a': user_id})
|
||||
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})
|
||||
|
||||
c.execute(
|
||||
'''select character_id, max_stamina_ts, stamina from user where user_id=?''', (user_id,))
|
||||
x = c.fetchone()
|
||||
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,))
|
||||
x = c.fetchone()
|
||||
|
||||
if Config.CHARACTER_FULL_UNLOCK:
|
||||
c.execute('''select level, exp from user_char_full where user_id = :a and character_id = :b''', {
|
||||
'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])
|
||||
else:
|
||||
flag = 0
|
||||
prog = 0
|
||||
overdrive = 0
|
||||
|
||||
c.execute('''select current_map from user where user_id = :a''', {
|
||||
'a': user_id})
|
||||
map_id = c.fetchone()[0]
|
||||
|
||||
if beyond_gauge == 0: # 是否是beyond挑战
|
||||
base_step = 2.5 + 2.45*rating**0.5
|
||||
step = base_step * (prog/50) * step_times
|
||||
else:
|
||||
info = get_world_info(map_id)
|
||||
if clear_type == 0:
|
||||
base_step = 8/9 + (rating/1.3)**0.5
|
||||
else:
|
||||
base_step = 8/3 + (rating/1.3)**0.5
|
||||
|
||||
if character_id in info['character_affinity']:
|
||||
affinity_multiplier = info['affinity_multiplier'][info['character_affinity'].index(
|
||||
character_id)]
|
||||
else:
|
||||
affinity_multiplier = 1
|
||||
|
||||
step = base_step * (prog/50) * step_times * affinity_multiplier
|
||||
|
||||
c.execute('''select * from user_world where user_id = :a and map_id =:b''',
|
||||
{'a': user_id, 'b': map_id})
|
||||
y = c.fetchone()
|
||||
if y[4] == 1: # 图不可用
|
||||
return {}
|
||||
|
||||
rewards, steps, curr_position, curr_capture, info = climb_step(
|
||||
user_id, map_id, step, y[3], y[2])
|
||||
for i in rewards: # 物品分发
|
||||
for j in i['items']:
|
||||
amount = j['amount'] if 'amount' in j else 1
|
||||
item_id = j['id'] if 'id' in j else ''
|
||||
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:
|
||||
exp, level = server.character.calc_level_up(
|
||||
c, user_id, character_id, exp, exp_times*rating*6)
|
||||
c.execute('''update user_char set level=?, exp=? where user_id=? and character_id=?''',
|
||||
(level, exp, user_id, character_id))
|
||||
else:
|
||||
exp = server.character.LEVEL_STEPS[level]
|
||||
|
||||
if beyond_gauge == 0:
|
||||
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'],
|
||||
"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:
|
||||
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'],
|
||||
"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 stamina_multiply != 1:
|
||||
re['stamina_multiply'] = stamina_multiply
|
||||
if fragment_multiply != 100:
|
||||
re['fragment_multiply'] = fragment_multiply
|
||||
if prog_boost_multiply != 0:
|
||||
re['prog_boost_multiply'] = prog_boost_multiply
|
||||
|
||||
if curr_position == info['step_count']-1 and info['is_repeatable']: # 循环图判断
|
||||
curr_position = 0
|
||||
c.execute('''update user_world set curr_position=:a, curr_capture=:b where user_id=:c and map_id=:d''', {
|
||||
'a': curr_position, 'b': curr_capture, 'c': user_id, 'd': map_id})
|
||||
|
||||
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
|
||||
|
||||
@@ -1,54 +1,86 @@
|
||||
import sqlite3
|
||||
import hashlib
|
||||
import time
|
||||
import server.arcworld
|
||||
from server.sql import Connect
|
||||
import functools
|
||||
from setting import Config
|
||||
from flask import jsonify
|
||||
|
||||
BAN_TIME = [1, 3, 7, 15, 31]
|
||||
|
||||
|
||||
def arc_login(name: str, password: str) -> str: # 登录判断
|
||||
# 查询数据库中的user表,验证账号密码,返回并记录token,多返回个error code
|
||||
def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判断
|
||||
# 查询数据库中的user表,验证账号密码,返回并记录token,多返回个error code和extra
|
||||
# token采用user_id和时间戳连接后hash生成(真的是瞎想的,没用bear)
|
||||
# 密码和token的加密方式为 SHA-256
|
||||
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
error_code = None
|
||||
error_code = 108
|
||||
token = None
|
||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||
c.execute('''select user_id, password from user where name = :name''', {
|
||||
'name': name})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
if x[1] == '':
|
||||
# 账号封禁
|
||||
error_code = 106
|
||||
elif x[1] == hash_pwd:
|
||||
user_id = str(x[0])
|
||||
with Connect() as c:
|
||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||
c.execute('''select user_id, password, ban_flag from user where name = :name''', {
|
||||
'name': name})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
now = int(time.time() * 1000)
|
||||
token = hashlib.sha256(
|
||||
(user_id + str(now)).encode("utf8")).hexdigest()
|
||||
c.execute(
|
||||
'''select exists(select * from login where user_id = :user_id)''', {"user_id": user_id})
|
||||
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] == '':
|
||||
# 账号封禁
|
||||
error_code = 106
|
||||
elif x[1] == hash_pwd:
|
||||
user_id = str(x[0])
|
||||
token = hashlib.sha256(
|
||||
(user_id + str(now)).encode("utf8")).hexdigest()
|
||||
c.execute(
|
||||
'''select login_device from login where user_id = :user_id''', {"user_id": user_id})
|
||||
y = c.fetchall()
|
||||
if y:
|
||||
device_list = []
|
||||
for i in y:
|
||||
if i[0]:
|
||||
device_list.append(i[0])
|
||||
else:
|
||||
device_list.append('')
|
||||
|
||||
if c.fetchone() == (1,): # 删掉多余token
|
||||
c.execute('''delete from login where user_id = :user_id''',
|
||||
{'user_id': user_id})
|
||||
should_delete_num = len(
|
||||
device_list) + 1 - Config.LOGIN_DEVICE_NUMBER_LIMIT
|
||||
|
||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
||||
'user_id': user_id, 'access_token': token})
|
||||
if not Config.ALLOW_LOGIN_SAME_DEVICE:
|
||||
if device_id in device_list: # 对相同设备进行删除
|
||||
c.execute('''delete from login where login_device=:a and user_id=:b''', {
|
||||
'a': device_id, 'b': user_id})
|
||||
should_delete_num = len(
|
||||
device_list) + 1 - device_list.count(device_id) - Config.LOGIN_DEVICE_NUMBER_LIMIT
|
||||
|
||||
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);''',
|
||||
{'user_id': user_id, 'a': int(should_delete_num)})
|
||||
|
||||
c.execute('''insert into login values(:access_token, :user_id, :time, :ip, :device_id)''', {
|
||||
'user_id': user_id, 'access_token': token, 'device_id': device_id, 'time': now, 'ip': ip})
|
||||
error_code = None
|
||||
else:
|
||||
# 密码错误
|
||||
error_code = 104
|
||||
else:
|
||||
# 密码错误
|
||||
# 用户名错误
|
||||
error_code = 104
|
||||
else:
|
||||
# 用户名错误
|
||||
error_code = 104
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return token, error_code
|
||||
return token, error_code, None
|
||||
|
||||
|
||||
def arc_register(name: str, password: str): # 注册
|
||||
# 账号注册,只记录hash密码和用户名,生成user_id和user_code,自动登录返回token
|
||||
def arc_register(name: str, password: str, device_id: str, email: str, ip: str): # 注册
|
||||
# 账号注册,记录hash密码、用户名和邮箱,生成user_id和user_code,自动登录返回token
|
||||
# token和密码的处理同登录部分
|
||||
|
||||
def build_user_code(c):
|
||||
@@ -73,76 +105,128 @@ def arc_register(name: str, password: str): # 注册
|
||||
return 2000001
|
||||
|
||||
def insert_user_char(c, user_id):
|
||||
# 为用户添加所有可用角色
|
||||
c.execute('''select * from character''')
|
||||
# 为用户添加初始角色
|
||||
c.execute('''insert into user_char values(?,?,?,?,?,?)''',
|
||||
(user_id, 0, 1, 0, 0, 0))
|
||||
c.execute('''insert into user_char values(?,?,?,?,?,?)''',
|
||||
(user_id, 1, 1, 0, 0, 0))
|
||||
c.execute('''select character_id, max_level, is_uncapped from character''')
|
||||
x = c.fetchall()
|
||||
if x != []:
|
||||
if x:
|
||||
for i in x:
|
||||
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
||||
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
||||
exp = 25000 if i[1] == 30 else 10000
|
||||
c.execute('''insert into user_char_full values(?,?,?,?,?,?)''',
|
||||
(user_id, i[0], i[1], exp, i[2], 0))
|
||||
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||
c.execute(
|
||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
||||
if c.fetchone() == (0,):
|
||||
user_code = build_user_code(c)
|
||||
user_id = build_user_id(c)
|
||||
now = int(time.time() * 1000)
|
||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket)
|
||||
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0, '', 0)
|
||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
||||
'user_id': user_id})
|
||||
user_id = None
|
||||
token = None
|
||||
error_code = 108
|
||||
with Connect() as c:
|
||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||
c.execute(
|
||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute(
|
||||
'''select exists(select * from user where email = :email)''', {'email': email})
|
||||
if c.fetchone() == (0,):
|
||||
user_code = build_user_code(c)
|
||||
user_id = build_user_id(c)
|
||||
now = int(time.time() * 1000)
|
||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket, prog_boost, email)
|
||||
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0, '', :memories, 0, :email)
|
||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd, 'memories': Config.DEFAULT_MEMORIES, 'email': email})
|
||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
||||
'user_id': user_id})
|
||||
|
||||
token = hashlib.sha256(
|
||||
(str(user_id) + str(now)).encode("utf8")).hexdigest()
|
||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
||||
'user_id': user_id, 'access_token': token})
|
||||
token = hashlib.sha256(
|
||||
(str(user_id) + str(now)).encode("utf8")).hexdigest()
|
||||
c.execute('''insert into login values(:access_token, :user_id, :time, :ip, :device_id)''', {
|
||||
'user_id': user_id, 'access_token': token, 'device_id': device_id, 'time': now, 'ip': ip})
|
||||
|
||||
insert_user_char(c, user_id)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return user_id, token, 0
|
||||
else:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None, None, 101
|
||||
insert_user_char(c, user_id)
|
||||
error_code = 0
|
||||
else:
|
||||
error_code = 102
|
||||
else:
|
||||
error_code = 101
|
||||
|
||||
return user_id, token, error_code
|
||||
|
||||
|
||||
def token_get_id(token: str):
|
||||
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
||||
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select user_id from login where access_token = :token''', {
|
||||
'token': token})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return x[0]
|
||||
else:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
user_id = None
|
||||
with Connect() as c:
|
||||
c.execute('''select user_id from login where access_token = :token''', {
|
||||
'token': token})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
user_id = x[0]
|
||||
|
||||
return user_id
|
||||
|
||||
|
||||
def code_get_id(user_code):
|
||||
# 用user_code获取id
|
||||
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select user_id from user where user_code = :a''',
|
||||
{'a': user_code})
|
||||
user_id = None
|
||||
|
||||
with Connect() as c:
|
||||
c.execute('''select user_id from user where user_code = :a''',
|
||||
{'a': user_code})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
user_id = x[0]
|
||||
|
||||
return user_id
|
||||
|
||||
|
||||
def auth_required(request):
|
||||
# arcaea登录验证,写成了修饰器
|
||||
def decorator(view):
|
||||
@functools.wraps(view)
|
||||
def wrapped_view(*args, **kwargs):
|
||||
|
||||
user_id = None
|
||||
headers = request.headers
|
||||
|
||||
if 'AppVersion' in headers: # 版本检查
|
||||
if Config.ALLOW_APPVERSION:
|
||||
if headers['AppVersion'] not in Config.ALLOW_APPVERSION:
|
||||
return jsonify({"success": False, "error_code": 5})
|
||||
|
||||
if 'Authorization' in headers:
|
||||
token = headers['Authorization']
|
||||
token = token[7:]
|
||||
user_id = token_get_id(token)
|
||||
|
||||
if user_id is not None:
|
||||
return view(user_id, *args, **kwargs)
|
||||
else:
|
||||
return jsonify({"success": False, "error_code": 108})
|
||||
|
||||
return wrapped_view
|
||||
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 is not None:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return x[0]
|
||||
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:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
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
|
||||
|
||||
256
latest version/server/character.py
Normal file
256
latest version/server/character.py
Normal file
@@ -0,0 +1,256 @@
|
||||
from setting import Config
|
||||
from server.sql import Connect
|
||||
import server.info
|
||||
import server.item
|
||||
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):
|
||||
# int与布尔值转换
|
||||
if x is None or x == 0:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def get_level_steps():
|
||||
# 返回level_steps字典数组
|
||||
return [{'level': i, 'level_exp': LEVEL_STEPS[i]} for i in LEVEL_STEPS]
|
||||
|
||||
|
||||
def calc_char_value(level, value1, value20, value30):
|
||||
# 计算搭档数值的核心函数,返回浮点数
|
||||
|
||||
def calc_char_value_20(level, stata, statb, lva=1, lvb=20):
|
||||
# 计算1~20级搭档数值的核心函数,返回浮点数,来自https://redive.estertion.win/arcaea/calc/
|
||||
|
||||
n = [0, 0, 0.0005831753900000081, 0.004665403120000065, 0.015745735529959858, 0.03732322495992008, 0.07289692374980007, 0.12596588423968, 0.2000291587694801, 0.29858579967923987, 0.42513485930893946,
|
||||
0.5748651406910605, 0.7014142003207574, 0.7999708412305152, 0.8740341157603029, 0.9271030762501818, 0.962676775040091, 0.9842542644700301, 0.9953345968799998, 0.9994168246100001, 1]
|
||||
e = n[lva] - n[lvb]
|
||||
a = stata - statb
|
||||
r = a / e
|
||||
d = stata - n[lva] * r
|
||||
|
||||
return d + r * n[level]
|
||||
|
||||
def calc_char_value_30(level, stata, statb, lva=20, lvb=30):
|
||||
# 计算21~30级搭档数值,返回浮点数
|
||||
|
||||
return (level - lva) * (statb - stata) / (lvb - lva) + stata
|
||||
|
||||
if level < 1 or level > 30:
|
||||
return 0
|
||||
elif 1 <= level <= 20:
|
||||
return calc_char_value_20(level, value1, value20)
|
||||
else:
|
||||
return calc_char_value_30(level, value20, value30)
|
||||
|
||||
|
||||
def get_char_core(c, character_id):
|
||||
# 得到对应角色觉醒所需的核心,返回字典列表
|
||||
r = []
|
||||
c.execute(
|
||||
'''select item_id, amount from char_item where character_id = ? and type="core"''', (character_id,))
|
||||
x = c.fetchall()
|
||||
if x:
|
||||
for i in x:
|
||||
r.append({'core_type': i[0], 'amount': i[1]})
|
||||
return r
|
||||
|
||||
|
||||
def get_user_characters(c, user_id):
|
||||
# 获取用户所拥有角色,返回列表
|
||||
|
||||
c.execute('''select character_id from user_char where user_id = :user_id''',
|
||||
{'user_id': user_id})
|
||||
|
||||
x = c.fetchall()
|
||||
characters = []
|
||||
|
||||
if x:
|
||||
for i in x:
|
||||
characters.append(i[0])
|
||||
|
||||
return characters
|
||||
|
||||
|
||||
def get_user_character(c, user_id):
|
||||
# 得到用户拥有的角色列表,返回列表
|
||||
|
||||
if Config.CHARACTER_FULL_UNLOCK:
|
||||
c.execute('''select * from user_char_full a,character b where a.user_id = :user_id and a.character_id=b.character_id''',
|
||||
{'user_id': user_id})
|
||||
else:
|
||||
c.execute('''select * from user_char a,character b where a.user_id = :user_id and a.character_id=b.character_id''',
|
||||
{'user_id': user_id})
|
||||
x = c.fetchall()
|
||||
if not x and not Config.CHARACTER_FULL_UNLOCK:
|
||||
# 添加初始角色
|
||||
c.execute('''insert into user_char values(?,?,?,?,?,?)''',
|
||||
(user_id, 0, 1, 0, 0, 0))
|
||||
c.execute('''insert into user_char values(?,?,?,?,?,?)''',
|
||||
(user_id, 1, 1, 0, 0, 0))
|
||||
c.execute('''select * from user_char a,character b where a.user_id = :user_id and a.character_id=b.character_id''',
|
||||
{'user_id': user_id})
|
||||
x = c.fetchall()
|
||||
|
||||
if not x:
|
||||
return []
|
||||
r = []
|
||||
for i in x:
|
||||
|
||||
char = {
|
||||
"is_uncapped_override": int2b(i[5]),
|
||||
"is_uncapped": int2b(i[4]),
|
||||
"uncap_cores": get_char_core(c, i[1]),
|
||||
"char_type": i[22],
|
||||
"skill_id_uncap": i[21],
|
||||
"skill_requires_uncap": int2b(i[20]),
|
||||
"skill_unlock_level": i[19],
|
||||
"skill_id": i[18],
|
||||
"overdrive": calc_char_value(i[2], i[11], i[14], i[17]),
|
||||
"prog": calc_char_value(i[2], i[10], i[13], i[16]),
|
||||
"frag": calc_char_value(i[2], i[9], i[12], i[15]),
|
||||
"level_exp": LEVEL_STEPS[i[2]],
|
||||
"exp": i[3],
|
||||
"level": i[2],
|
||||
"name": i[7],
|
||||
"character_id": i[1]
|
||||
}
|
||||
if i[1] == 21:
|
||||
char["voice"] = [0, 1, 2, 3, 100, 1000, 1001]
|
||||
r.append(char)
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def get_one_character(c, user_id, character_id):
|
||||
# 得到用户某个拥有的角色列表,返回字典
|
||||
|
||||
if Config.CHARACTER_FULL_UNLOCK:
|
||||
c.execute('''select * from user_char_full a,character b where a.user_id = :user_id and a.character_id=b.character_id and a.character_id=:a''',
|
||||
{'user_id': user_id, 'a': character_id})
|
||||
else:
|
||||
c.execute('''select * from user_char a,character b where a.user_id = :user_id and a.character_id=b.character_id and a.character_id=:a''',
|
||||
{'user_id': user_id, 'a': character_id})
|
||||
x = c.fetchone()
|
||||
if not x:
|
||||
return {}
|
||||
r = {
|
||||
"is_uncapped_override": int2b(x[5]),
|
||||
"is_uncapped": int2b(x[4]),
|
||||
"uncap_cores": get_char_core(c, x[1]),
|
||||
"char_type": x[22],
|
||||
"skill_id_uncap": x[21],
|
||||
"skill_requires_uncap": int2b(x[20]),
|
||||
"skill_unlock_level": x[19],
|
||||
"skill_id": x[18],
|
||||
"overdrive": calc_char_value(x[2], x[11], x[14], x[17]),
|
||||
"prog": calc_char_value(x[2], x[10], x[13], x[16]),
|
||||
"frag": calc_char_value(x[2], x[9], x[12], x[15]),
|
||||
"level_exp": LEVEL_STEPS[x[2]],
|
||||
"exp": x[3],
|
||||
"level": x[2],
|
||||
"name": x[7],
|
||||
"character_id": x[1]
|
||||
}
|
||||
if x[1] == 21:
|
||||
r["voice"] = [0, 1, 2, 3, 100, 1000, 1001]
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def calc_level_up(c, user_id, character_id, exp, exp_addition):
|
||||
# 计算角色升级,返回当前经验和等级
|
||||
|
||||
exp += exp_addition
|
||||
|
||||
if exp >= LEVEL_STEPS[20]: # 未觉醒溢出
|
||||
c.execute('''select is_uncapped from user_char where user_id=? and character_id=?''',
|
||||
(user_id, character_id))
|
||||
x = c.fetchone()
|
||||
if x and x[0] == 0:
|
||||
return LEVEL_STEPS[20], 20
|
||||
|
||||
a = []
|
||||
b = []
|
||||
for i in LEVEL_STEPS:
|
||||
a.append(i)
|
||||
b.append(LEVEL_STEPS[i])
|
||||
|
||||
if exp >= b[-1]: # 溢出
|
||||
return b[-1], a[-1]
|
||||
|
||||
if exp < b[0]: # 向下溢出,是异常状态
|
||||
return 0, 1
|
||||
|
||||
i = len(a) - 1
|
||||
while exp < b[i]:
|
||||
i -= 1
|
||||
|
||||
return exp, a[i]
|
||||
|
||||
|
||||
def char_use_core(user_id, character_id, amount):
|
||||
# 以太之滴升级,返回user_id,core状态,角色状态的字典
|
||||
r = None
|
||||
with Connect() as c:
|
||||
|
||||
c.execute(
|
||||
'''select amount from user_item where user_id=? and item_id="core_generic" and type="core"''', (user_id,))
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
pre_amount = x[0]
|
||||
else:
|
||||
pre_amount = 0
|
||||
|
||||
if amount <= pre_amount:
|
||||
c.execute(
|
||||
'''select exp from user_char where user_id=? and character_id=?''', (user_id, character_id))
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
exp, level = calc_level_up(
|
||||
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=?''',
|
||||
(level, exp, user_id, character_id))
|
||||
server.item.claim_user_item(
|
||||
c, user_id, 'core_generic', 'core', -amount)
|
||||
|
||||
r = {'character': [get_one_character(c, user_id, character_id)]}
|
||||
r['cores'] = server.item.get_user_cores(c, user_id)
|
||||
r['user_id'] = user_id
|
||||
return r
|
||||
|
||||
|
||||
def char_uncap(user_id, character_id):
|
||||
# 角色觉醒,返回user_id,core状态,角色状态的字典
|
||||
r = None
|
||||
with Connect() as c:
|
||||
c.execute('''select * from char_item where character_id=?''',
|
||||
(character_id,))
|
||||
x = c.fetchall()
|
||||
if not x:
|
||||
return None
|
||||
|
||||
success = True
|
||||
for i in x:
|
||||
c.execute(
|
||||
'''select amount from user_item where user_id=? and item_id=? and type=?''', (user_id, i[1], i[2]))
|
||||
y = c.fetchone()
|
||||
if not y or i[3] > y[0]:
|
||||
success = False
|
||||
break
|
||||
|
||||
if success:
|
||||
c.execute('''update user_char set is_uncapped=1, is_uncapped_override=0 where user_id=? and 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['cores'] = server.item.get_user_cores(c, user_id)
|
||||
r['user_id'] = user_id
|
||||
return r
|
||||
@@ -1,7 +1,15 @@
|
||||
import sqlite3
|
||||
from server.sql import Connect
|
||||
import server.arcworld
|
||||
import server.arcpurchase
|
||||
import server.arcdownload
|
||||
import server.character
|
||||
import server.item
|
||||
import time
|
||||
from setting import Config
|
||||
|
||||
MAX_STAMINA = 12
|
||||
STAMINA_RECOVER_TICK = 1800000
|
||||
CORE_EXP = 250
|
||||
|
||||
|
||||
def int2b(x):
|
||||
@@ -44,47 +52,6 @@ def get_recent_score(c, user_id):
|
||||
return []
|
||||
|
||||
|
||||
def get_user_character(c, user_id):
|
||||
# 得到用户拥有的角色列表,返回列表
|
||||
c.execute('''select * from user_char where user_id = :user_id''',
|
||||
{'user_id': user_id})
|
||||
x = c.fetchall()
|
||||
if x != []:
|
||||
s = []
|
||||
for i in x:
|
||||
char_name = ''
|
||||
c.execute(
|
||||
'''select name from character where character_id = :x''', {'x': i[1]})
|
||||
y = c.fetchone()
|
||||
if y is not None:
|
||||
char_name = y[0]
|
||||
char = {
|
||||
"is_uncapped_override": int2b(i[14]),
|
||||
"is_uncapped": int2b(i[13]),
|
||||
"uncap_cores": [],
|
||||
"char_type": i[12],
|
||||
"skill_id_uncap": i[11],
|
||||
"skill_requires_uncap": int2b(i[10]),
|
||||
"skill_unlock_level": i[9],
|
||||
"skill_id": i[8],
|
||||
"overdrive": i[7],
|
||||
"prog": i[6],
|
||||
"frag": i[5],
|
||||
"level_exp": i[4],
|
||||
"exp": i[3],
|
||||
"level": i[2],
|
||||
"name": char_name,
|
||||
"character_id": i[1]
|
||||
}
|
||||
if i[1] == 21:
|
||||
char["voice"] = [0, 1, 2, 3, 100, 1000, 1001]
|
||||
s.append(char)
|
||||
|
||||
return s
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_user_friend(c, user_id):
|
||||
# 得到用户的朋友列表,返回列表
|
||||
c.execute('''select user_id_other from friend where user_id_me = :user_id''', {
|
||||
@@ -109,19 +76,27 @@ def get_user_friend(c, user_id):
|
||||
is_char_uncapped_override = int2b(y[9])
|
||||
if y[23] != -1:
|
||||
character = y[23]
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id=:a and character_id=:b''', {
|
||||
'a': i[0], 'b': character})
|
||||
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''', {
|
||||
'a': i[0], 'b': character})
|
||||
else:
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char_full where user_id=:a and character_id=:b''', {
|
||||
'a': i[0], 'b': character})
|
||||
z = c.fetchone()
|
||||
if z:
|
||||
is_char_uncapped = int2b(z[0])
|
||||
is_char_uncapped_override = int2b(z[1])
|
||||
|
||||
rating = y[5]
|
||||
if int2b(y[10]):
|
||||
rating = -1
|
||||
|
||||
s.append({
|
||||
"is_mutual": is_mutual,
|
||||
"is_char_uncapped_override": is_char_uncapped_override,
|
||||
"is_char_uncapped": is_char_uncapped,
|
||||
"is_skill_sealed": int2b(y[7]),
|
||||
"rating": y[5],
|
||||
"rating": rating,
|
||||
"join_date": int(y[3]),
|
||||
"character": character,
|
||||
"recent_score": get_recent_score(c, i[0]),
|
||||
@@ -129,54 +104,72 @@ def get_user_friend(c, user_id):
|
||||
"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
|
||||
|
||||
|
||||
def get_user_singles(c, user_id):
|
||||
# 得到用户的单曲,返回列表
|
||||
c.execute('''select * from user_item where user_id = :user_id and type = "single"''',
|
||||
{'user_id': user_id})
|
||||
x = c.fetchall()
|
||||
if not x:
|
||||
return []
|
||||
|
||||
re = []
|
||||
for i in x:
|
||||
re.append(i[1])
|
||||
return re
|
||||
|
||||
|
||||
def get_user_packs(c, user_id):
|
||||
# 得到用户的曲包,返回列表
|
||||
c.execute('''select * from user_item where user_id = :user_id and type = "pack"''',
|
||||
{'user_id': user_id})
|
||||
x = c.fetchall()
|
||||
if not x:
|
||||
return []
|
||||
|
||||
re = []
|
||||
for i in x:
|
||||
re.append(i[1])
|
||||
return re
|
||||
|
||||
|
||||
def get_value_0(c, user_id):
|
||||
# 构造value id=0的数据,返回字典
|
||||
def get_user_me(c, user_id):
|
||||
# 构造user/me的数据,返回字典
|
||||
c.execute('''select * from user where user_id = :x''', {'x': user_id})
|
||||
x = c.fetchone()
|
||||
r = {}
|
||||
if x is not None:
|
||||
user_character = get_user_character(c, user_id)
|
||||
user_character = server.character.get_user_character(c, user_id)
|
||||
# 下面没有使用get_user_characters函数是为了节省一次查询
|
||||
characters = []
|
||||
for i in user_character:
|
||||
characters.append(i['character_id'])
|
||||
|
||||
r = {"is_aprilfools": False,
|
||||
"curr_available_maps": [],
|
||||
character_id = x[6]
|
||||
if character_id not in characters:
|
||||
character_id = 0
|
||||
c.execute(
|
||||
'''update user set character_id=0 where user_id=?''', (user_id,))
|
||||
|
||||
favorite_character_id = x[23]
|
||||
if favorite_character_id not in characters: # 这是考虑有可能favourite_character设置了用户未拥有的角色
|
||||
favorite_character_id = -1
|
||||
c.execute(
|
||||
'''update user set favorite_character=-1 where user_id=?''', (user_id,))
|
||||
|
||||
# 计算世界排名
|
||||
c.execute(
|
||||
'''select world_rank_score from user where user_id=?''', (user_id,))
|
||||
y = c.fetchone()
|
||||
if y and y[0]:
|
||||
c.execute(
|
||||
'''select count(*) from user where world_rank_score > ?''', (y[0],))
|
||||
y = c.fetchone()
|
||||
if y and y[0] + 1 <= Config.WORLD_RANK_MAX:
|
||||
world_rank = y[0] + 1
|
||||
else:
|
||||
world_rank = 0
|
||||
else:
|
||||
world_rank = 0
|
||||
|
||||
# 源点强化
|
||||
prog_boost = 0
|
||||
if x[27] and x[27] != 0:
|
||||
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,
|
||||
"curr_available_maps": server.arcworld.get_available_maps(),
|
||||
"character_stats": user_character,
|
||||
"friends": get_user_friend(c, user_id),
|
||||
"settings": {
|
||||
"favorite_character": x[23],
|
||||
"favorite_character": favorite_character_id,
|
||||
"is_hide_rating": int2b(x[10]),
|
||||
"max_stamina_notification_enabled": int2b(x[24])
|
||||
},
|
||||
@@ -185,25 +178,25 @@ def get_value_0(c, user_id):
|
||||
"user_code": x[4],
|
||||
"display_name": x[1],
|
||||
"ticket": x[26],
|
||||
"character": x[6],
|
||||
"character": character_id,
|
||||
"is_locked_name_duplicate": False,
|
||||
"is_skill_sealed": int2b(x[7]),
|
||||
"current_map": x[25],
|
||||
"prog_boost": 0,
|
||||
"next_fragstam_ts": -1,
|
||||
"max_stamina_ts": 1586274871917,
|
||||
"stamina": 12,
|
||||
"world_unlocks": ["scenery_chap1", "scenery_chap2", "scenery_chap3", "scenery_chap4", "scenery_chap5"],
|
||||
"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"],
|
||||
"singles": get_user_singles(c, user_id), # ["dataerror", "yourvoiceso", "crosssoul", "impurebird", "auxesia", "modelista", "yozakurafubuki", "surrender", "metallicpunisher", "carminescythe", "bethere", "callmyname", "fallensquare", "dropdead", "alexandrite", "astraltale", "phantasia", "empireofwinter", "libertas", "dottodot", "dreadnought", "mirzam", "heavenlycaress", "filament", "avantraze", "battlenoone", "saikyostronger", "izana", "einherjar", "laqryma", "amygdata", "altale", "feelssoright", "scarletcage", "teriqma", "mahoroba", "badtek", "maliciousmischance", "buchigireberserker", "galaxyfriends", "xeraphinite", "xanatos"]
|
||||
"packs": get_user_packs(c, user_id),
|
||||
# ["vs", "extend", "dynamix", "prelude", "core", "yugamu", "omatsuri", "zettai", "mirai", "shiawase", "chunithm", "nijuusei", "groovecoaster", "rei", "tonesphere", "lanota"]
|
||||
"prog_boost": prog_boost,
|
||||
"next_fragstam_ts": next_fragstam_ts,
|
||||
"max_stamina_ts": max_stamina_ts,
|
||||
"stamina": server.arcworld.calc_stamina(max_stamina_ts, stamina),
|
||||
"world_unlocks": server.item.get_user_items(c, user_id, 'world_unlock'),
|
||||
"world_songs": server.item.get_user_items(c, user_id, 'world_song'),
|
||||
"singles": server.item.get_user_items(c, user_id, 'single'),
|
||||
"packs": server.item.get_user_items(c, user_id, 'pack'),
|
||||
"characters": characters,
|
||||
"cores": [],
|
||||
"cores": server.item.get_user_cores(c, user_id),
|
||||
"recent_score": get_recent_score(c, user_id),
|
||||
"max_friend": 50,
|
||||
"rating": x[5],
|
||||
"join_date": int(x[3])
|
||||
"join_date": int(x[3]),
|
||||
"global_rank": world_rank
|
||||
}
|
||||
|
||||
return r
|
||||
@@ -211,148 +204,56 @@ def get_value_0(c, user_id):
|
||||
|
||||
def arc_aggregate_small(user_id):
|
||||
# 返回用户数据
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
r = {"success": True,
|
||||
"value": [{
|
||||
"id": 0,
|
||||
"value": get_value_0(c, user_id)
|
||||
}]}
|
||||
r = {"success": False}
|
||||
with Connect() as c:
|
||||
r = {"success": True,
|
||||
"value": [{
|
||||
"id": 0,
|
||||
"value": get_user_me(c, user_id)
|
||||
}]}
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return r
|
||||
|
||||
|
||||
def arc_aggregate_big(user_id):
|
||||
# 返回用户数据和地图歌曲信息
|
||||
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
r = {"success": True,
|
||||
"value": [{
|
||||
"id": 0,
|
||||
"value": get_value_0(c, user_id)
|
||||
}, {
|
||||
"id": 1,
|
||||
"value": server.arcpurchase.get_item(c, 'pack')
|
||||
}, {
|
||||
"id": 2,
|
||||
"value": {}
|
||||
}, {
|
||||
"id": 3,
|
||||
"value": {
|
||||
"max_stamina": 12,
|
||||
"stamina_recover_tick": 1800000,
|
||||
"core_exp": 250,
|
||||
"curr_ts": int(time.time())*1000,
|
||||
"level_steps": [{
|
||||
"level": 1,
|
||||
"level_exp": 0
|
||||
}, {
|
||||
"level": 2,
|
||||
"level_exp": 50
|
||||
}, {
|
||||
"level": 3,
|
||||
"level_exp": 100
|
||||
}, {
|
||||
"level": 4,
|
||||
"level_exp": 150
|
||||
}, {
|
||||
"level": 5,
|
||||
"level_exp": 200
|
||||
}, {
|
||||
"level": 6,
|
||||
"level_exp": 300
|
||||
}, {
|
||||
"level": 7,
|
||||
"level_exp": 450
|
||||
}, {
|
||||
"level": 8,
|
||||
"level_exp": 650
|
||||
}, {
|
||||
"level": 9,
|
||||
"level_exp": 900
|
||||
}, {
|
||||
"level": 10,
|
||||
"level_exp": 1200
|
||||
}, {
|
||||
"level": 11,
|
||||
"level_exp": 1600
|
||||
}, {
|
||||
"level": 12,
|
||||
"level_exp": 2100
|
||||
}, {
|
||||
"level": 13,
|
||||
"level_exp": 2700
|
||||
}, {
|
||||
"level": 14,
|
||||
"level_exp": 3400
|
||||
}, {
|
||||
"level": 15,
|
||||
"level_exp": 4200
|
||||
}, {
|
||||
"level": 16,
|
||||
"level_exp": 5100
|
||||
}, {
|
||||
"level": 17,
|
||||
"level_exp": 6100
|
||||
}, {
|
||||
"level": 18,
|
||||
"level_exp": 7200
|
||||
}, {
|
||||
"level": 19,
|
||||
"level_exp": 8500
|
||||
}, {
|
||||
"level": 20,
|
||||
"level_exp": 10000
|
||||
}, {
|
||||
"level": 21,
|
||||
"level_exp": 11500
|
||||
}, {
|
||||
"level": 22,
|
||||
"level_exp": 13000
|
||||
}, {
|
||||
"level": 23,
|
||||
"level_exp": 14500
|
||||
}, {
|
||||
"level": 24,
|
||||
"level_exp": 16000
|
||||
}, {
|
||||
"level": 25,
|
||||
"level_exp": 17500
|
||||
}, {
|
||||
"level": 26,
|
||||
"level_exp": 19000
|
||||
}, {
|
||||
"level": 27,
|
||||
"level_exp": 20500
|
||||
}, {
|
||||
"level": 28,
|
||||
"level_exp": 22000
|
||||
}, {
|
||||
"level": 29,
|
||||
"level_exp": 23500
|
||||
}, {
|
||||
"level": 30,
|
||||
"level_exp": 25000
|
||||
}],
|
||||
"world_ranking_enabled": False,
|
||||
"is_byd_chapter_unlocked": True
|
||||
# 返回比较全的用户数据
|
||||
r = {"success": False}
|
||||
with Connect() as c:
|
||||
# 防止数据库锁
|
||||
id_2 = server.arcdownload.get_all_songs(user_id, url_flag=False)
|
||||
id_5 = {
|
||||
"current_map": server.arcworld.get_current_map(user_id),
|
||||
"user_id": user_id,
|
||||
"maps": server.arcworld.get_world_all(user_id)
|
||||
}
|
||||
r = {"success": True,
|
||||
"value": [{
|
||||
"id": 0,
|
||||
"value": get_user_me(c, user_id)
|
||||
}, {
|
||||
"id": 1,
|
||||
"value": server.arcpurchase.get_purchase(c, 'pack')
|
||||
}, {
|
||||
"id": 2,
|
||||
"value": id_2
|
||||
}, {
|
||||
"id": 3,
|
||||
"value": {
|
||||
"max_stamina": MAX_STAMINA,
|
||||
"stamina_recover_tick": STAMINA_RECOVER_TICK,
|
||||
"core_exp": CORE_EXP,
|
||||
"curr_ts": int(time.time()*1000),
|
||||
"level_steps": server.character.get_level_steps(),
|
||||
"world_ranking_enabled": True,
|
||||
"is_byd_chapter_unlocked": True
|
||||
}
|
||||
}, {
|
||||
"id": 4,
|
||||
"value": server.arcpurchase.get_user_present(c, user_id)
|
||||
}, {
|
||||
"id": 5,
|
||||
"value": id_5
|
||||
}
|
||||
}, {
|
||||
"id": 4,
|
||||
"value": server.arcpurchase.get_user_present(c, user_id)
|
||||
}, {
|
||||
"id": 5,
|
||||
"value": {
|
||||
"current_map": server.arcworld.get_current_map(user_id),
|
||||
"user_id": user_id,
|
||||
"maps": server.arcworld.get_world_all(user_id)
|
||||
}
|
||||
}
|
||||
]}
|
||||
]}
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return r
|
||||
|
||||
98
latest version/server/init.py
Normal file
98
latest version/server/init.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import os
|
||||
from shutil import copy, copy2
|
||||
from server.sql import Connect
|
||||
from database.database_initialize import main, ARCAEA_SERVER_VERSION
|
||||
from web.system import update_database
|
||||
|
||||
|
||||
def try_rename(path, new_path):
|
||||
# 尝试重命名文件,并尝试避免命名冲突,返回最终路径
|
||||
final_path = new_path
|
||||
if os.path.exists(new_path):
|
||||
i = 1
|
||||
while os.path.exists(new_path + str(i)):
|
||||
i += 1
|
||||
os.rename(path, new_path + str(i))
|
||||
final_path = new_path + str(i)
|
||||
else:
|
||||
os.rename(path, new_path)
|
||||
|
||||
return final_path
|
||||
|
||||
|
||||
def check_before_run(app):
|
||||
# 运行前检查关键文件,返回布尔值,其实是因为有人经常忘了
|
||||
|
||||
f = True
|
||||
|
||||
if not os.path.exists('setting.py'):
|
||||
app.logger.warning('File `setting.py` is missing.')
|
||||
f = False
|
||||
|
||||
if not os.path.exists('database'):
|
||||
app.logger.warning('Folder `database` is missing.')
|
||||
f = False
|
||||
|
||||
if not os.path.exists('database/songs'):
|
||||
app.logger.warning('Folder `database/songs` is missing.')
|
||||
f = False
|
||||
|
||||
if not os.path.exists('database/arcaea_database.db'):
|
||||
app.logger.warning('File `database/arcaea_database.db` is missing.')
|
||||
f = False
|
||||
try:
|
||||
app.logger.info(
|
||||
'Try to new the file `database/arcaea_database.db`.')
|
||||
main('./database/')
|
||||
app.logger.info(
|
||||
'Success to new the file `database/arcaea_database.db`.')
|
||||
f = True
|
||||
except:
|
||||
app.logger.warning(
|
||||
'Fail to new the file `database/arcaea_database.db`.')
|
||||
|
||||
else:
|
||||
with Connect() as c:
|
||||
try:
|
||||
c.execute('''select value from config where id="version"''')
|
||||
x = c.fetchone()
|
||||
except:
|
||||
x = None
|
||||
|
||||
# 数据库自动更新,不强求
|
||||
if not x or x[0] != ARCAEA_SERVER_VERSION:
|
||||
app.logger.warning(
|
||||
'Maybe the file `database/arcaea_database.db` is an old version.')
|
||||
try:
|
||||
app.logger.info(
|
||||
'Try to update the file `database/arcaea_database.db`.')
|
||||
|
||||
path = try_rename('database/arcaea_database.db',
|
||||
'database/arcaea_database.db.bak')
|
||||
|
||||
try:
|
||||
copy2(path, 'database/arcaea_database.db')
|
||||
except:
|
||||
copy(path, 'database/arcaea_database.db')
|
||||
|
||||
if os.path.isfile("database/old_arcaea_database.db"):
|
||||
os.remove('database/old_arcaea_database.db')
|
||||
|
||||
try_rename('database/arcaea_database.db',
|
||||
'database/old_arcaea_database.db')
|
||||
|
||||
main('./database/')
|
||||
update_database()
|
||||
|
||||
app.logger.info(
|
||||
'Success to update the file `database/arcaea_database.db`.')
|
||||
|
||||
except:
|
||||
app.logger.warning(
|
||||
'Fail to update the file `database/arcaea_database.db`.')
|
||||
|
||||
if not os.path.exists('database/arcsong.db'):
|
||||
app.logger.warning('File `database/arcsong.db` is missing.')
|
||||
f = False
|
||||
|
||||
return f
|
||||
106
latest version/server/item.py
Normal file
106
latest version/server/item.py
Normal file
@@ -0,0 +1,106 @@
|
||||
from setting import Config
|
||||
|
||||
|
||||
def get_user_items(c, user_id, item_type):
|
||||
# 得到用户的物品,返回列表,不包含数量信息
|
||||
|
||||
if item_type == 'world_song' and Config.WORLD_SONG_FULL_UNLOCK or item_type == 'world_unlock' and Config.WORLD_SCENERY_FULL_UNLOCK:
|
||||
c.execute('''select item_id from item where type=?''', (item_type,))
|
||||
else:
|
||||
c.execute('''select item_id from user_item where user_id = :user_id and type = :item_type''',
|
||||
{'user_id': user_id, 'item_type': item_type})
|
||||
x = c.fetchall()
|
||||
if not x:
|
||||
return []
|
||||
|
||||
re = []
|
||||
for i in x:
|
||||
re.append(i[0])
|
||||
return re
|
||||
|
||||
|
||||
def get_user_cores(c, user_id):
|
||||
# 得到用户的core,返回字典列表
|
||||
r = []
|
||||
c.execute(
|
||||
'''select item_id, amount from user_item where user_id = ? and type="core"''', (user_id,))
|
||||
x = c.fetchall()
|
||||
if x:
|
||||
for i in x:
|
||||
if i[1]:
|
||||
amount = i[1]
|
||||
else:
|
||||
amount = 0
|
||||
r.append({'core_type': i[0], 'amount': amount})
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def claim_user_item(c, user_id, item_id, item_type, amount=1):
|
||||
# 处理用户物品,包括添加和删除操作,返回成功与否布尔值
|
||||
# 这个接口允许memory变成负数,所以不能用来购买
|
||||
|
||||
try:
|
||||
amount = int(amount)
|
||||
except:
|
||||
return False
|
||||
|
||||
if item_type not in ['memory', 'character']:
|
||||
c.execute('''select is_available from item where item_id=? and type=?''',
|
||||
(item_id, item_type))
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
if x[0] == 0:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if item_type == 'core':
|
||||
c.execute(
|
||||
'''select amount from user_item where user_id=? and item_id=? and type="core"''', (user_id, item_id))
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
if x[0] + amount < 0: # 数量不足
|
||||
return False
|
||||
c.execute('''update user_item set amount=? where user_id=? and item_id=? and type="core"''',
|
||||
(x[0]+amount, user_id, item_id))
|
||||
else:
|
||||
if amount < 0: # 添加数量错误
|
||||
return False
|
||||
c.execute('''insert into user_item values(?,?,"core",?)''',
|
||||
(user_id, item_id, amount))
|
||||
|
||||
elif item_type == 'memory':
|
||||
c.execute('''select ticket from user where user_id=?''', (user_id,))
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
c.execute('''update user set ticket=? where user_id=?''',
|
||||
(x[0]+amount, user_id))
|
||||
else:
|
||||
return False
|
||||
|
||||
elif item_type == 'character':
|
||||
if not item_id.isdigit():
|
||||
c.execute(
|
||||
'''select character_id from character where name=?''', (item_id,))
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
character_id = x[0]
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
character_id = int(item_id)
|
||||
c.execute(
|
||||
'''select exists(select * from user_char where user_id=? and character_id=?)''', (user_id, character_id))
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into user_char values(?,?,1,0,0,0)''',
|
||||
(user_id, character_id))
|
||||
|
||||
elif item_type in ['world_song', 'world_unlock', 'single', 'pack']:
|
||||
c.execute('''select exists(select * from user_item where user_id=? and item_id=? and type=?)''',
|
||||
(user_id, item_id, item_type))
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into user_item values(:a,:b,:c,1)''',
|
||||
{'a': user_id, 'b': item_id, 'c': item_type})
|
||||
|
||||
return True
|
||||
@@ -1,5 +1,7 @@
|
||||
import sqlite3
|
||||
from server.sql import Connect
|
||||
from setting import Config
|
||||
import server.info
|
||||
import server.character
|
||||
|
||||
|
||||
def b2int(x):
|
||||
@@ -20,98 +22,105 @@ def int2b(x):
|
||||
|
||||
def change_char(user_id, character_id, skill_sealed):
|
||||
# 角色改变,包括技能封印的改变,返回成功与否的布尔值
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
x = c.fetchone()
|
||||
if x is not None:
|
||||
re = False
|
||||
|
||||
with Connect() as c:
|
||||
if Config.CHARACTER_FULL_UNLOCK:
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char_full where user_id = :a and character_id = :b''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
else:
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
x = c.fetchone()
|
||||
if x:
|
||||
is_uncapped = x[0]
|
||||
is_uncapped_override = x[1]
|
||||
else:
|
||||
return False
|
||||
|
||||
if skill_sealed == 'false':
|
||||
skill_sealed = False
|
||||
else:
|
||||
skill_sealed = True
|
||||
c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
||||
'a': b2int(skill_sealed), 'b': character_id, 'c': x[0], 'd': x[1], 'e': user_id})
|
||||
'a': b2int(skill_sealed), 'b': character_id, 'c': is_uncapped, 'd': is_uncapped_override, 'e': user_id})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
re = True
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return False
|
||||
return re
|
||||
|
||||
|
||||
def change_char_uncap(user_id, character_id):
|
||||
# 角色觉醒改变,返回字典
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
x = c.fetchone()
|
||||
r = None
|
||||
if x is not None and x[0] == 1:
|
||||
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
||||
'a': b2int(x[1] == 0), 'b': user_id})
|
||||
c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
||||
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
||||
c.execute('''select * from user_char where user_id = :a and character_id = :b''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
y = c.fetchone()
|
||||
c.execute(
|
||||
'''select name from character where character_id = :x''', {'x': y[1]})
|
||||
z = c.fetchone()
|
||||
if z is not None:
|
||||
char_name = z[0]
|
||||
if y is not None:
|
||||
r = {
|
||||
"is_uncapped_override": int2b(y[14]),
|
||||
"is_uncapped": int2b(y[13]),
|
||||
"uncap_cores": [],
|
||||
"char_type": y[12],
|
||||
"skill_id_uncap": y[11],
|
||||
"skill_requires_uncap": int2b(y[10]),
|
||||
"skill_unlock_level": y[9],
|
||||
"skill_id": y[8],
|
||||
"overdrive": y[7],
|
||||
"prog": y[6],
|
||||
"frag": y[5],
|
||||
"level_exp": y[4],
|
||||
"exp": y[3],
|
||||
"level": y[2],
|
||||
"name": char_name,
|
||||
"character_id": y[1]
|
||||
}
|
||||
with Connect() as c:
|
||||
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''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
else:
|
||||
c.execute('''select is_uncapped, is_uncapped_override from user_char_full where user_id = :a and character_id = :b''',
|
||||
{'a': user_id, 'b': character_id})
|
||||
x = c.fetchone()
|
||||
|
||||
if x is not None and x[0] == 1:
|
||||
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
||||
'a': b2int(x[1] == 0), 'b': user_id})
|
||||
|
||||
if not Config.CHARACTER_FULL_UNLOCK:
|
||||
c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
||||
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
||||
c.execute(
|
||||
'''select * from user_char a,character b where a.user_id=? and a.character_id=b.character_id and a.character_id=?''', (user_id, character_id))
|
||||
else:
|
||||
c.execute('''update user_char_full set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
||||
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
||||
c.execute(
|
||||
'''select * from user_char_full a,character b where a.user_id=? and a.character_id=b.character_id and a.character_id=?''', (user_id, character_id))
|
||||
y = c.fetchone()
|
||||
if y is not None:
|
||||
r = {
|
||||
"is_uncapped_override": int2b(y[5]),
|
||||
"is_uncapped": int2b(y[4]),
|
||||
"uncap_cores": server.character.get_char_core(c, y[1]),
|
||||
"char_type": y[22],
|
||||
"skill_id_uncap": y[21],
|
||||
"skill_requires_uncap": int2b(y[20]),
|
||||
"skill_unlock_level": y[19],
|
||||
"skill_id": y[18],
|
||||
"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]),
|
||||
"frag": server.character.calc_char_value(y[2], y[9], y[12], y[15]),
|
||||
"level_exp": server.character.LEVEL_STEPS[y[2]],
|
||||
"exp": y[3],
|
||||
"level": y[2],
|
||||
"name": y[7],
|
||||
"character_id": y[1]
|
||||
}
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return r
|
||||
|
||||
|
||||
def arc_sys_set(user_id, value, set_arg):
|
||||
# 三个设置,PTT隐藏、体力满通知、最爱角色,无返回
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
if 'favorite_character' in set_arg:
|
||||
value = int(value)
|
||||
c.execute('''update user set favorite_character = :a where user_id = :b''', {
|
||||
'a': value, 'b': user_id})
|
||||
with Connect() as c:
|
||||
if 'favorite_character' in set_arg:
|
||||
value = int(value)
|
||||
c.execute('''update user set favorite_character = :a where user_id = :b''', {
|
||||
'a': value, 'b': user_id})
|
||||
|
||||
else:
|
||||
if value == 'false':
|
||||
value = False
|
||||
else:
|
||||
value = True
|
||||
if value == 'false':
|
||||
value = False
|
||||
else:
|
||||
value = True
|
||||
|
||||
if 'is_hide_rating' in set_arg:
|
||||
c.execute('''update user set is_hide_rating = :a where user_id = :b''', {
|
||||
'a': b2int(value), 'b': user_id})
|
||||
if 'max_stamina_notification_enabled' in set_arg:
|
||||
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
|
||||
'a': b2int(value), 'b': user_id})
|
||||
if 'is_hide_rating' in set_arg:
|
||||
c.execute('''update user set is_hide_rating = :a where user_id = :b''', {
|
||||
'a': b2int(value), 'b': user_id})
|
||||
if 'max_stamina_notification_enabled' in set_arg:
|
||||
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
|
||||
'a': b2int(value), 'b': user_id})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return None
|
||||
|
||||
|
||||
@@ -119,37 +128,32 @@ def arc_add_friend(user_id, friend_id):
|
||||
# 加好友,返回好友列表,或者是错误码602、604
|
||||
if user_id == friend_id:
|
||||
return 604
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||
{'x': user_id, 'y': friend_id})
|
||||
|
||||
r = None
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into friend values(:a, :b)''',
|
||||
{'a': user_id, 'b': friend_id})
|
||||
r = server.info.get_user_friend(c, user_id)
|
||||
with Connect() as c:
|
||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||
{'x': user_id, 'y': friend_id})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into friend values(:a, :b)''',
|
||||
{'a': user_id, 'b': friend_id})
|
||||
r = server.info.get_user_friend(c, user_id)
|
||||
else:
|
||||
r = 602
|
||||
|
||||
else:
|
||||
return 602
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return r
|
||||
|
||||
|
||||
def arc_delete_friend(user_id, friend_id):
|
||||
# 删好友,返回好友列表
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||
{'x': user_id, 'y': friend_id})
|
||||
r = None
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
||||
with Connect() as c:
|
||||
|
||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||
{'x': user_id, 'y': friend_id})
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
||||
{'x': user_id, 'y': friend_id})
|
||||
|
||||
r = server.info.get_user_friend(c, user_id)
|
||||
r = server.info.get_user_friend(c, user_id)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return r
|
||||
|
||||
80
latest version/server/sql.py
Normal file
80
latest version/server/sql.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import sqlite3
|
||||
from flask import current_app
|
||||
import traceback
|
||||
|
||||
|
||||
class Connect():
|
||||
# 数据库连接类,上下文管理
|
||||
|
||||
def __init__(self, file_path='./database/arcaea_database.db'):
|
||||
"""
|
||||
数据库连接,默认连接arcaea_database.db
|
||||
接受:文件路径
|
||||
返回:sqlite3连接操作对象
|
||||
"""
|
||||
self.file_path = file_path
|
||||
|
||||
def __enter__(self):
|
||||
self.conn = sqlite3.connect(self.file_path)
|
||||
self.c = self.conn.cursor()
|
||||
return self.c
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if self.conn:
|
||||
self.conn.commit()
|
||||
self.conn.close()
|
||||
|
||||
if exc_type is not None:
|
||||
current_app.logger.error(
|
||||
traceback.format_exception(exc_type, exc_val, exc_tb))
|
||||
|
||||
return True
|
||||
|
||||
class Sql():
|
||||
|
||||
@staticmethod
|
||||
def select(c, table_name, target_column=[], limit=-1, offset=0, query={}, sort=[]):
|
||||
# 执行查询单句sql语句,返回fetchall数据
|
||||
# 使用准确查询,且在单表内
|
||||
|
||||
sql = 'select '
|
||||
sql_dict = {}
|
||||
if len(target_column) >= 2:
|
||||
sql += target_column[0]
|
||||
for i in range(1, len(target_column)):
|
||||
sql += ',' + target_column[i]
|
||||
sql += ' from ' + table_name
|
||||
elif len(target_column) == 1:
|
||||
sql += target_column[0] + ' from ' + table_name
|
||||
else:
|
||||
sql += '* from ' + table_name
|
||||
|
||||
where_field = []
|
||||
where_value = []
|
||||
for i in query:
|
||||
where_field.append(i)
|
||||
where_value.append(query[i])
|
||||
|
||||
if where_field and where_value:
|
||||
sql += ' where '
|
||||
sql += where_field[0] + '=:' + where_field[0]
|
||||
sql_dict[where_field[0]] = where_value[0]
|
||||
if len(where_field) >= 2:
|
||||
for i in range(1, len(where_field)):
|
||||
sql_dict[where_field[i]] = where_value[i]
|
||||
sql += ' and ' + where_field[i] + '=:' + where_field[i]
|
||||
|
||||
if sort:
|
||||
sql += ' order by ' + sort[0]['column'] + ' ' + sort[0]['order']
|
||||
if len(sort) >= 2:
|
||||
for i in range(1, len(sort)):
|
||||
sql += ', ' + sort[i]['column'] + ' ' + sort[i]['order']
|
||||
|
||||
if limit >= 0:
|
||||
sql += ' limit :limit offset :offset'
|
||||
sql_dict['limit'] = limit
|
||||
sql_dict['offset'] = offset
|
||||
|
||||
c.execute(sql, sql_dict)
|
||||
|
||||
return c.fetchall()
|
||||
@@ -1,7 +0,0 @@
|
||||
[CONFIG]
|
||||
HOST = 192.168.1.113
|
||||
PORT = 80
|
||||
|
||||
[WEB]
|
||||
USERNAME = admin
|
||||
PASSWORD = admin
|
||||
230
latest version/setting.py
Normal file
230
latest version/setting.py
Normal file
@@ -0,0 +1,230 @@
|
||||
class Config():
|
||||
'''
|
||||
This is the setting file. You can change some parameters here.
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
主机的地址和端口号
|
||||
Host and port of your server
|
||||
'''
|
||||
HOST = '192.168.1.101'
|
||||
PORT = '80'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
游戏API地址前缀
|
||||
Game API's URL prefix
|
||||
'''
|
||||
GAME_API_PREFIX = '/kusoatui/15'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
允许使用的游戏版本,若为空,则默认全部允许
|
||||
Allowed game versions
|
||||
If it is blank, all are allowed.
|
||||
'''
|
||||
ALLOW_APPVERSION = ['3.5.3', '3.5.3c', '3.7.0', '3.7.0c']
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
SSL证书路径
|
||||
留空则使用HTTP
|
||||
SSL certificate path
|
||||
If left blank, use HTTP.
|
||||
'''
|
||||
SSL_CERT = '' # *.pem
|
||||
SSL_KEY = '' # *.key
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
愚人节模式开关
|
||||
Switch of April Fool's Day
|
||||
'''
|
||||
IS_APRILFOOLS = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
世界排名的最大显示数量
|
||||
The largest number of global rank
|
||||
'''
|
||||
WORLD_RANK_MAX = 200
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
世界模式当前活动图设置
|
||||
Current available maps in world mode
|
||||
'''
|
||||
AVAILABLE_MAP = [] # Ex. ['test', 'test2']
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
Web后台管理页面的用户名和密码
|
||||
Username and password of web background management page
|
||||
'''
|
||||
USERNAME = 'admin'
|
||||
PASSWORD = 'admin'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
Web后台管理页面的session秘钥,如果不知道是什么,请不要修改
|
||||
Session key of web background management page
|
||||
If you don't know what it is, please don't modify it.
|
||||
'''
|
||||
SECRET_KEY = '1145141919810'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
API接口完全控制权限Token,留空则不使用
|
||||
API interface full control permission Token
|
||||
If you don't want to use it, leave it blank.
|
||||
'''
|
||||
API_TOKEN = '123'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
歌曲下载地址前缀,留空则自动获取
|
||||
Song download address prefix
|
||||
If left blank, it will be obtained automatically.
|
||||
'''
|
||||
DOWNLOAD_LINK_PREFIX = '' # http://***.com/download/
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
玩家歌曲下载的24小时次数限制,每个文件算一次
|
||||
Player's song download limit times in 24 hours, once per file
|
||||
'''
|
||||
DOWNLOAD_TIMES_LIMIT = 3000
|
||||
'''
|
||||
歌曲下载链接的有效时长,单位:秒
|
||||
Effective duration of song download link, unit: seconds
|
||||
'''
|
||||
DOWNLOAD_TIME_GAP_LIMIT = 1000
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
Arcaea登录的最大允许设备数量,最小值为1
|
||||
The maximum number of devices allowed to log in Arcaea, minimum: 1
|
||||
'''
|
||||
LOGIN_DEVICE_NUMBER_LIMIT = 1
|
||||
'''
|
||||
是否允许同设备多应用共存登录
|
||||
请注意,这个选项设置为True时,下一个选项将自动变为False
|
||||
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
|
||||
'''
|
||||
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
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否记录详细的服务器日志
|
||||
If recording detailed server logs is enabled
|
||||
'''
|
||||
ALLOW_LOG_INFO = False
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
用户注册时的默认记忆源点数量
|
||||
The default amount of memories at the time of user registration
|
||||
'''
|
||||
DEFAULT_MEMORIES = 0
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否全解锁搭档
|
||||
If unlocking all partners is enabled
|
||||
'''
|
||||
CHARACTER_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否全解锁世界歌曲
|
||||
If unlocking all world songs is enabled
|
||||
'''
|
||||
WORLD_SONG_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否全解锁世界场景
|
||||
If unlocking all world scenerys is enabled
|
||||
'''
|
||||
WORLD_SCENERY_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否强制使用全解锁云端存档
|
||||
If forcing full unlocked cloud save is enabled
|
||||
'''
|
||||
SAVE_FULL_UNLOCK = False
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否使用最好的 10 条记录(而不是最近的 30 条记录中较好的 10 条)来计算 PTT
|
||||
Calculate PTT with best 10 instead of recent best 10
|
||||
'''
|
||||
USE_B10_AS_R10 = False
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
@@ -20,4 +20,4 @@
|
||||
{% endfor %} {% block content %}{% endblock %}
|
||||
</section>
|
||||
|
||||
<footer id="footer" class="footer">Made by Lost@2020</footer>
|
||||
<footer id="footer" class="footer">Made by Lost@2020-2021</footer>
|
||||
@@ -16,26 +16,54 @@
|
||||
<span class="char-name">{{char['name']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Level: </span>
|
||||
<span class="char-num">{{char['level']}}</span>
|
||||
<span>Max level: </span>
|
||||
<span class="char-num">{{char['max_level']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Frag: </span>
|
||||
<span class="char-num">{{char['frag']}}</span>
|
||||
<span>Frag-level 1: </span>
|
||||
<span class="char-num">{{char['frag1']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Prog: </span>
|
||||
<span class="char-num">{{char['prog']}}</span>
|
||||
<span>Prog-level 1: </span>
|
||||
<span class="char-num">{{char['prog1']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Overdrive: </span>
|
||||
<span class="char-num">{{char['overdrive']}}</span>
|
||||
<span>Overdrive-level 1: </span>
|
||||
<span class="char-num">{{char['overdrive1']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Frag-level 20: </span>
|
||||
<span class="char-num">{{char['frag20']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Prog-level 20: </span>
|
||||
<span class="char-num">{{char['prog20']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Overdrive-level 20: </span>
|
||||
<span class="char-num">{{char['overdrive20']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Frag-level 30: </span>
|
||||
<span class="char-num">{{char['frag30']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Prog-level 30: </span>
|
||||
<span class="char-num">{{char['prog30']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Overdrive-level 30: </span>
|
||||
<span class="char-num">{{char['overdrive30']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Skill id: </span>
|
||||
<span class="char-num">{{char['skill_id']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Skill unlock level: </span>
|
||||
<span class="char-num">{{char['skill_unlock_level']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Uncapped skill id: </span>
|
||||
<span class="char-num">{{char['skill_id_uncap']}}</span>
|
||||
<br />
|
||||
|
||||
@@ -20,24 +20,6 @@
|
||||
<span class="char-num">{{item['is_available']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Price: </span>
|
||||
<span class="char-num">{{item['price']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Original price: </span>
|
||||
<span class="char-num">{{item['orig_price']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Discount from: </span>
|
||||
<span class="char-num">{{item['discount_from']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Discount to: </span>
|
||||
<span class="char-num">{{item['discount_to']}}</span>
|
||||
<br />
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
{% if not loop.last %}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
<div class="name">{{user['name']}}
|
||||
<span class="rank">UID: {{user['user_id']}}</span>
|
||||
<span class="rank">User code: {{user['user_code']}}</span>
|
||||
{% if user['ban_flag'] %}
|
||||
<span class="rank">Banned</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
|
||||
<div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div>
|
||||
|
||||
@@ -20,10 +20,28 @@
|
||||
<span class="char-num">{{present['description']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Items: </span>
|
||||
<span class="char-num" style='white-space:pre'>{{present['items']}}</span>
|
||||
{% if present['items'] %}<br />
|
||||
{% for x in present['items'] %}
|
||||
<span>Item id: </span>
|
||||
<span class="char-num">{{x['item_id']}}</span>
|
||||
<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>
|
||||
{% if not loop.last %}
|
||||
|
||||
57
latest version/templates/web/allpurchase.html
Normal file
57
latest version/templates/web/allpurchase.html
Normal file
@@ -0,0 +1,57 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block header %}
|
||||
<h1>{% block title %}All purchases{% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if posts %}<br />
|
||||
{% for item in posts %}
|
||||
|
||||
<div class="char-item">
|
||||
<span>Name: </span>
|
||||
<span class="name">{{item['purchase_name']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Price: </span>
|
||||
<span class="char-num">{{item['price']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Original price: </span>
|
||||
<span class="char-num">{{item['orig_price']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Discount from: </span>
|
||||
<span class="char-num">{{item['discount_from']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Discount to: </span>
|
||||
<span class="char-num">{{item['discount_to']}}</span>
|
||||
<br />
|
||||
{% if item['items'] %}<br />
|
||||
{% for x in item['items'] %}
|
||||
<span>Item id: </span>
|
||||
<span class="char-num">{{x['item_id']}}</span>
|
||||
<br />
|
||||
|
||||
<span>Item type: </span>
|
||||
<span class="char-num">{{x['type']}}</span>
|
||||
<br />
|
||||
|
||||
|
||||
|
||||
{% if not loop.last %}
|
||||
<br />
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% if not loop.last %}
|
||||
<br />
|
||||
<hr />
|
||||
<br />
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -22,9 +22,28 @@
|
||||
</span>
|
||||
<br />
|
||||
|
||||
<span>Items: </span>
|
||||
<span class="char-num" style='white-space:pre'>{{redeem['items']}}</span>
|
||||
{% if redeem['items'] %}<br />
|
||||
{% for x in redeem['items'] %}
|
||||
<span>Item id: </span>
|
||||
<span class="char-num">{{x['item_id']}}</span>
|
||||
<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>
|
||||
|
||||
@@ -12,15 +12,6 @@
|
||||
<label for="level">Level</label>
|
||||
<input name="level" id="level">
|
||||
|
||||
<label for="frag">Frag</label>
|
||||
<input name="frag" id="frag">
|
||||
|
||||
<label for="prog">Prog</label>
|
||||
<input name="prog" id="prog">
|
||||
|
||||
<label for="overdrive">Overdrive</label>
|
||||
<input name="overdrive" id="overdrive">
|
||||
|
||||
<div>
|
||||
<select name="skill_id">
|
||||
<option value="">Skill id</option>
|
||||
|
||||
@@ -5,37 +5,43 @@
|
||||
|
||||
{% block content %}
|
||||
<form action="/web/changeitem" method="post">
|
||||
<div class="title">Change the item</div>
|
||||
<div class="title">Add the item</div>
|
||||
<label for="item_id">ID of the item</label>
|
||||
<input name="item_id" id="item_id" required>
|
||||
<label for="type">Type</label>
|
||||
<div>
|
||||
<select name="type">
|
||||
<option value='single'>Single</option>
|
||||
<option value='single' selected>Single</option>
|
||||
<option value='pack'>Pack</option>
|
||||
<option value='world_song'>World song</option>
|
||||
<option value='character'>Character</option>
|
||||
</select>
|
||||
</div>
|
||||
<br />
|
||||
<div class="content">可修改项 Modifiable items:</div>
|
||||
<div><label for="is_available">是否可用 Is available:</label>
|
||||
<br />
|
||||
<br />
|
||||
<label><input type="radio" name="is_available" value=1>True</label>
|
||||
<label><input type="radio" name="is_available" checked value=1>True</label>
|
||||
<br />
|
||||
<label><input type="radio" name="is_available" value=0>False</label>
|
||||
</div>
|
||||
<label for="price">Price</label>
|
||||
<input name="price" id="price">
|
||||
<label for="orig_price">Original price</label>
|
||||
<input name="orig_price" id="orig_price">
|
||||
<label for="discount_from">Discount from</label>
|
||||
<input type="datetime-local" name="discount_from" id="discount_from">
|
||||
<label for="discount_to">Discount to</label>
|
||||
<input type="datetime-local" name="discount_to" id="discount_to">
|
||||
<div class="content">如果某些不需要修改,留空即可</div>
|
||||
<div class="content">If some things do not need to be modified, leave it blank.</div>
|
||||
<div class="content">时间填写是一个HTML5控件</div>
|
||||
<div class="content">Time filling is an HTML5 control.</div>
|
||||
<input type="submit" value="Edit">
|
||||
<br />
|
||||
<input type="submit" value="Add">
|
||||
</form>
|
||||
<form action="/web/changeitem/delete" method="post">
|
||||
<div class="title">Delete the item</div>
|
||||
<label for="item_id">ID of the item</label>
|
||||
<input name="item_id" id="item_id" required>
|
||||
<label for="type">Type</label>
|
||||
<div>
|
||||
<select name="type">
|
||||
<option value='single' selected>Single</option>
|
||||
<option value='pack'>Pack</option>
|
||||
<option value='world_song'>World song</option>
|
||||
<option value='character'>Character</option>
|
||||
</select>
|
||||
</div>
|
||||
<br />
|
||||
<input type="submit" value="Delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -14,15 +14,25 @@
|
||||
<label for="expire_ts">Expire time</label>
|
||||
<input type="datetime-local" name="expire_ts" id="expire_ts" required>
|
||||
<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>
|
||||
<div class="content">There can only be one of the two kinds of present. Please leave the other one blank. If you
|
||||
fill both, the memories will be given priority.</div>
|
||||
<label for="item_id">ID of the item</label>
|
||||
<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='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">Time filling is an HTML5 control.</div>
|
||||
<input type="submit" value="Add">
|
||||
|
||||
32
latest version/templates/web/changepurchase.html
Normal file
32
latest version/templates/web/changepurchase.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block header %}
|
||||
<h1>{% block title %}Change the purchases{% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="/web/changepurchase" method="post">
|
||||
<div class="title">Add the purchase</div>
|
||||
<label for="purchase_name">Purchase name</label>
|
||||
<input name="purchase_name" id="purchase_name" required>
|
||||
<label for="price">Price</label>
|
||||
<input name="price" id="price">
|
||||
<label for="orig_price">Original price</label>
|
||||
<input name="orig_price" id="orig_price">
|
||||
<label for="discount_from">Discount from</label>
|
||||
<input type="datetime-local" name="discount_from" id="discount_from">
|
||||
<label for="discount_to">Discount to</label>
|
||||
<input type="datetime-local" name="discount_to" id="discount_to">
|
||||
<div class="content">时间填写是一个HTML5控件</div>
|
||||
<div class="content">Time filling is an HTML5 control.</div>
|
||||
<br />
|
||||
<input type="submit" value="Add">
|
||||
</form>
|
||||
|
||||
<form action="/web/changepurchase/delete" method="post">
|
||||
<div class="title">Delete the purchase</div>
|
||||
<label for="purchase_name">Purchase name</label>
|
||||
<input name="purchase_name" id="purchase_name" required>
|
||||
<br />
|
||||
<input type="submit" value="Delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
44
latest version/templates/web/changepurchaseitem.html
Normal file
44
latest version/templates/web/changepurchaseitem.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block header %}
|
||||
<h1>{% block title %}Change the purchase's items{% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="/web/changepurchaseitem" method="post">
|
||||
<div class="title">Add the purchase's item</div>
|
||||
<label for="purchase_name">Purchase name</label>
|
||||
<input name="purchase_name" id="purchase_name" required>
|
||||
<label for="item_id">ID of the item</label>
|
||||
<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='character'>Character</option>
|
||||
</select>
|
||||
</div>
|
||||
<br />
|
||||
<input type="submit" value="Add">
|
||||
</form>
|
||||
|
||||
<form action="/web/changepurchaseitem/delete" method="post">
|
||||
<div class="title">Delete the purchase's item</div>
|
||||
<label for="purchase_name">Purchase name</label>
|
||||
<input name="purchase_name" id="purchase_name" required>
|
||||
<label for="item_id">ID of the item</label>
|
||||
<input name="item_id" id="item_id" required>
|
||||
<label for="type">Type</label>
|
||||
<div>
|
||||
<select name="type">
|
||||
<option value='single' selected>Single</option>
|
||||
<option value='pack'>Pack</option>
|
||||
<option value='world_song'>World song</option>
|
||||
<option value='character'>Character</option>
|
||||
</select>
|
||||
</div>
|
||||
<br />
|
||||
<input type="submit" value="Delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -11,27 +11,40 @@
|
||||
<input name="code" id="code">
|
||||
<div>Or</div>
|
||||
<div>随机批量生成 Batch generation at random</div>
|
||||
<label for="amount">Amount</label>
|
||||
<input name="amount" id="amount">
|
||||
<label for="redeem_amount">Redeem code amount</label>
|
||||
<input name="redeem_amount" id="redeem_amount">
|
||||
<br />
|
||||
<div>Type:
|
||||
<div>Redeem code type:
|
||||
<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 />
|
||||
<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>
|
||||
|
||||
|
||||
<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>
|
||||
<div class="content">You can have both kinds of items. Please leave it blank if you don't need it.</div>
|
||||
<label for="item_id">ID of the item</label>
|
||||
<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">The length of redeem code is 10 ~ 20.</div>
|
||||
<div class="content">随机生成数量不得超过1000。</div>
|
||||
|
||||
38
latest version/templates/web/changescore.html
Normal file
38
latest version/templates/web/changescore.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block header %}
|
||||
<h1>{% block title %}Change the scores{% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="/web/changescore/delete" method="post">
|
||||
<div class="title">Delete the scores</div>
|
||||
<label for="sid">SID of the song</label>
|
||||
<input name="sid" id="sid">
|
||||
|
||||
<label for="difficulty">Difficulty</label>
|
||||
<select name='difficulty' id='difficulty'>
|
||||
<option value="-1" selected>All</option>
|
||||
<option value="0">Past</option>
|
||||
<option value="1">Present</option>
|
||||
<option value="2">Future</option>
|
||||
<option value="3">Beyond</option>
|
||||
</select>
|
||||
<br />
|
||||
|
||||
<label for="name">Arcaea Username</label>
|
||||
<input name="name" id="name">
|
||||
or<br />
|
||||
<label for="user_code">Arcaea User Code</label>
|
||||
<input name="user_code" id="user_code">
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div class="content">上述三项是查询参数,如果留空,则被认为是全部,都不填则认为是错误的。</div>
|
||||
<div class="content">The above three are query parameters. If they are left blank, they are considered all. However,
|
||||
if you don't fill in all of them, it's wrong.</div>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<input type="submit" value="Delete">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -19,7 +19,7 @@
|
||||
<input name="rating_ftr" id="rating_ftr" required>
|
||||
<label for="rating_byd">Beyond chart const</label>
|
||||
<input name="rating_byd" id="rating_byd" required>
|
||||
<div class="content">如果没有某个铺面,应该填入-1。</div>
|
||||
<div class="content">如果没有某个谱面,应该填入-1。</div>
|
||||
<div class="content">If there is no some chart, fill in -1 please.</div>
|
||||
<input type="submit" value="Add">
|
||||
</form>
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
<a href="{{ url_for('index.single_player_score') }}">单个玩家成绩查询 Single player score</a></br></br>
|
||||
<a href="{{ url_for('index.single_player_ptt') }}">单个玩家PTT详情查询 Single player ptt</a></br></br>
|
||||
<a href="{{ url_for('index.all_player') }}">所有玩家信息查询 All players</a></br></br>
|
||||
<a href="{{ url_for('index.all_song') }}">铺面信息查询 All songs</a></br></br>
|
||||
<a href="{{ url_for('index.all_song') }}">谱面信息查询 All songs</a></br></br>
|
||||
<a href="{{ url_for('index.all_character') }}">角色信息查询 All characters</a></br></br>
|
||||
<a href="{{ url_for('index.all_item') }}">购买信息查询 All items</a></br></br>
|
||||
<a href="{{ url_for('index.all_item') }}">物品信息查询 All items</a></br></br>
|
||||
<a href="{{ url_for('index.all_purchase') }}">购买信息查询 All purchases</a></br></br>
|
||||
<a href="{{ url_for('index.all_present') }}">奖励信息查询 All presents</a></br></br>
|
||||
<a href="{{ url_for('index.all_redeem') }}">兑换码信息查询 All redeem codes</a></br></br>
|
||||
<a href="{{ url_for('index.single_chart_top') }}">单个铺面排行榜查询 Single song chart tops</a>
|
||||
@@ -24,10 +25,13 @@
|
||||
<a href="{{ url_for('index.update_database') }}">数据库更新 Update databases</a></br></br>
|
||||
<a href="{{ url_for('index.edit_userpwd') }}">用户密码修改 Change user password</a></br></br>
|
||||
<a href="{{ url_for('index.ban_user') }}">封禁用户 Ban the user</a></br></br>
|
||||
<a href="{{ url_for('index.change_score') }}">成绩删除 Delete the scores</a></br></br>
|
||||
<a href="{{ url_for('index.update_user_save') }}">用户存档更新 Update user saves</a></br></br>
|
||||
<a href="{{ url_for('index.change_song') }}">歌曲修改 Change the songs</a></br></br>
|
||||
<a href="{{ url_for('index.change_character') }}">角色修改 Change the characters</a></br></br>
|
||||
<a href="{{ url_for('index.change_item') }}">购买信息修改 Change the items</a></br></br>
|
||||
<a href="{{ url_for('index.change_item') }}">物品信息修改 Change the items</a></br></br>
|
||||
<a href="{{ url_for('index.change_purchase') }}">购买信息修改 Change the purchases</a></br></br>
|
||||
<a href="{{ url_for('index.change_purchase_item') }}">购买信息的物品修改 Change the purchase items</a></br></br>
|
||||
<a href="{{ url_for('index.change_user') }}">用户信息修改 Change user information</a></br></br>
|
||||
<a href="{{ url_for('index.change_user_purchase') }}">用户购买信息修改 Change user purchase information</a></br></br>
|
||||
<a href="{{ url_for('index.change_present') }}">奖励修改 Change the presents</a></br></br>
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
<div class="name">{{user['name']}}
|
||||
<span class="rank">UID: {{user['user_id']}}</span>
|
||||
<span class="rank">User code: {{user['user_code']}}</span>
|
||||
{% if user['ban_flag'] %}
|
||||
<span class="rank">Banned</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
|
||||
<div class="ptt">Memories: {{user['ticket']}}</div>
|
||||
@@ -161,7 +164,7 @@
|
||||
{% if recent %}
|
||||
<div class="title">Recent 30</div>
|
||||
{% for i in recent %}
|
||||
|
||||
|
||||
{% if i %}
|
||||
<div class="score-item">
|
||||
<span class="song-title">
|
||||
|
||||
@@ -10,12 +10,34 @@
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
<div class="content">
|
||||
这里可以将旧版本的数据库同步到新版本的数据库,并刷新用户拥有的角色列表。<br />
|
||||
这里可以将旧版本的数据库同步到新版本的数据库,并刷新用户拥有的全角色列表。<br />
|
||||
可上传文件: arcaea_database.db和arcsong.db<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 />
|
||||
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.
|
||||
</div>
|
||||
<br />
|
||||
<hr />
|
||||
<form action="/web/updatedatabase/refreshsonghash" method="post">
|
||||
<div class="title">Refresh songs' hash</div>
|
||||
<br />
|
||||
<input type="submit" value="Refresh">
|
||||
|
||||
<div class="content">这里可以刷新储存在数据库中的songs文件夹下所有文件的Hash值。目的是应对歌曲谱面文件的更新。</div>
|
||||
<div class="content">Here you can refresh the hash values of all the files stored in the songs folder in the
|
||||
database. The purpose is to deal with the updating of songs' files.</div>
|
||||
</form>
|
||||
<br />
|
||||
<hr />
|
||||
<form action="/web/updatedatabase/refreshsongrating" method="post">
|
||||
<div class="title">Refresh songs' rating</div>
|
||||
<br />
|
||||
<input type="submit" value="Refresh">
|
||||
|
||||
<div class="content">这里可以刷新数据库中所有成绩的评分。目的是应对歌曲谱面定数的更新。</div>
|
||||
<div class="content">Here you can refresh the ratings of all scores in the database. The purpose is to deal
|
||||
with the updating of songs' chart consts.</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,8 @@
|
||||
from flask import (Blueprint, flash, g, redirect,
|
||||
render_template, request, session, url_for)
|
||||
import functools
|
||||
import configparser
|
||||
from setting import Config
|
||||
import hashlib
|
||||
|
||||
bp = Blueprint('login', __name__, url_prefix='/web')
|
||||
|
||||
@@ -15,18 +16,16 @@ def login():
|
||||
password = request.form['password']
|
||||
error = None
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
path = r'setting.ini'
|
||||
config.read(path, encoding="utf-8")
|
||||
USERNAME = config.get('WEB', 'USERNAME')
|
||||
PASSWORD = config.get('WEB', 'PASSWORD')
|
||||
|
||||
if username != USERNAME and password != PASSWORD:
|
||||
if username != Config.USERNAME or password != Config.PASSWORD:
|
||||
error = '错误的用户名或密码 Incorrect username or password.'
|
||||
|
||||
if error is None:
|
||||
session.clear()
|
||||
session['user_id'] = USERNAME + PASSWORD
|
||||
hash_session = username + \
|
||||
hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||
hash_session = hashlib.sha256(
|
||||
hash_session.encode("utf8")).hexdigest()
|
||||
session['user_id'] = hash_session
|
||||
return redirect(url_for('index.index'))
|
||||
|
||||
flash(error)
|
||||
@@ -48,16 +47,14 @@ def login_required(view):
|
||||
def wrapped_view(**kwargs):
|
||||
x = session.get('user_id')
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
path = r'setting.ini'
|
||||
config.read(path, encoding="utf-8")
|
||||
USERNAME = config.get('WEB', 'USERNAME')
|
||||
PASSWORD = config.get('WEB', 'PASSWORD')
|
||||
hash_session = Config.USERNAME + \
|
||||
hashlib.sha256(Config.PASSWORD.encode("utf8")).hexdigest()
|
||||
hash_session = hashlib.sha256(hash_session.encode("utf8")).hexdigest()
|
||||
|
||||
if x != USERNAME + PASSWORD:
|
||||
if x != hash_session:
|
||||
return redirect(url_for('login.login'))
|
||||
|
||||
g.user = {'user_id': x, 'username': USERNAME}
|
||||
g.user = {'user_id': x, 'username': Config.USERNAME}
|
||||
return view(**kwargs)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
import sqlite3
|
||||
from server.sql import Connect
|
||||
import time
|
||||
import json
|
||||
import server.arcscore
|
||||
@@ -161,64 +161,67 @@ def update_one_table(c1, c2, table_name):
|
||||
|
||||
def update_user_char(c):
|
||||
# 用character数据更新user_char
|
||||
c.execute('''select * from character''')
|
||||
c.execute('''select character_id, max_level, is_uncapped from character''')
|
||||
x = c.fetchall()
|
||||
c.execute('''select user_id from user''')
|
||||
y = c.fetchall()
|
||||
if x and y:
|
||||
for j in y:
|
||||
for i in x:
|
||||
c.execute('''delete from user_char where user_id=:a and character_id=:b''', {
|
||||
c.execute('''delete from user_char_full where user_id=:a and character_id=:b''', {
|
||||
'a': j[0], 'b': i[0]})
|
||||
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
||||
'a': j[0], 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
||||
exp = 25000 if i[1] == 30 else 10000
|
||||
c.execute('''insert into user_char_full values(?,?,?,?,?,?)''',
|
||||
(j[0], i[0], i[1], exp, i[2], 0))
|
||||
|
||||
|
||||
def update_database():
|
||||
# 将old数据库不存在数据加入到新数据库上,并删除old数据库
|
||||
# 对于arcaea_datebase.db,更新一些表,并用character数据更新user_char
|
||||
# 对于arcaea_datebase.db,更新一些表,并用character数据更新user_char_full
|
||||
# 对于arcsong.db,更新songs
|
||||
if os.path.isfile("database/old_arcaea_database.db") and os.path.isfile("database/arcaea_database.db"):
|
||||
conn1 = sqlite3.connect('./database/old_arcaea_database.db')
|
||||
c1 = conn1.cursor()
|
||||
conn2 = sqlite3.connect('./database/arcaea_database.db')
|
||||
c2 = conn2.cursor()
|
||||
with Connect('./database/old_arcaea_database.db') as c1:
|
||||
with Connect() as c2:
|
||||
|
||||
update_one_table(c1, c2, 'user')
|
||||
update_one_table(c1, c2, 'friend')
|
||||
update_one_table(c1, c2, 'best_score')
|
||||
update_one_table(c1, c2, 'recent30')
|
||||
update_one_table(c1, c2, 'user_world')
|
||||
update_one_table(c1, c2, 'item')
|
||||
update_one_table(c1, c2, 'user_item')
|
||||
update_one_table(c1, c2, 'user_save')
|
||||
update_one_table(c1, c2, 'login')
|
||||
update_one_table(c1, c2, 'present')
|
||||
update_one_table(c1, c2, 'user_present')
|
||||
update_one_table(c1, c2, 'redeem')
|
||||
update_one_table(c1, c2, 'user_redeem')
|
||||
update_one_table(c1, c2, 'user')
|
||||
update_one_table(c1, c2, 'friend')
|
||||
update_one_table(c1, c2, 'best_score')
|
||||
update_one_table(c1, c2, 'recent30')
|
||||
update_one_table(c1, c2, 'user_world')
|
||||
update_one_table(c1, c2, 'item')
|
||||
update_one_table(c1, c2, 'user_item')
|
||||
update_one_table(c1, c2, 'purchase')
|
||||
update_one_table(c1, c2, 'purchase_item')
|
||||
update_one_table(c1, c2, 'user_save')
|
||||
update_one_table(c1, c2, 'login')
|
||||
update_one_table(c1, c2, '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, 'user_redeem')
|
||||
update_one_table(c1, c2, 'redeem_item')
|
||||
update_one_table(c1, c2, 'role')
|
||||
update_one_table(c1, c2, 'user_role')
|
||||
update_one_table(c1, c2, 'power')
|
||||
update_one_table(c1, c2, 'role_power')
|
||||
update_one_table(c1, c2, 'api_auth')
|
||||
|
||||
update_user_char(c2)
|
||||
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
|
||||
|
||||
conn1.commit()
|
||||
conn1.close()
|
||||
conn2.commit()
|
||||
conn2.close()
|
||||
os.remove('database/old_arcaea_database.db')
|
||||
|
||||
# songs
|
||||
if os.path.isfile("database/old_arcsong.db") and os.path.isfile("database/arcsong.db"):
|
||||
conn1 = sqlite3.connect('./database/old_arcsong.db')
|
||||
c1 = conn1.cursor()
|
||||
conn2 = sqlite3.connect('./database/arcsong.db')
|
||||
c2 = conn2.cursor()
|
||||
with Connect('./database/old_arcsong.db') as c1:
|
||||
with Connect('./database/arcsong.db') as c2:
|
||||
|
||||
update_one_table(c1, c2, 'songs')
|
||||
update_one_table(c1, c2, 'songs')
|
||||
|
||||
conn1.commit()
|
||||
conn1.close()
|
||||
conn2.commit()
|
||||
conn2.close()
|
||||
os.remove('database/old_arcsong.db')
|
||||
|
||||
|
||||
@@ -227,14 +230,16 @@ def unlock_all_user_item(c):
|
||||
|
||||
c.execute('''select user_id from user''')
|
||||
x = c.fetchall()
|
||||
c.execute('''select item_id, type from item''')
|
||||
c.execute('''select item_id, type from purchase_item''')
|
||||
y = c.fetchall()
|
||||
c.execute('''delete from user_item''')
|
||||
if x and y:
|
||||
for i in x:
|
||||
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]})
|
||||
|
||||
return
|
||||
|
||||
@@ -242,49 +247,70 @@ def unlock_all_user_item(c):
|
||||
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()
|
||||
|
||||
for j in y:
|
||||
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]})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into user_item values(:a,:b,:c)''', {
|
||||
if c.fetchone() == (0,) and j[1] != 'character':
|
||||
c.execute('''insert into user_item values(:a,:b,:c,1)''', {
|
||||
'a': user_id, 'b': j[0], 'c': j[1]})
|
||||
|
||||
return
|
||||
|
||||
|
||||
def get_all_item():
|
||||
# 所有物品数据查询
|
||||
with Connect() as c:
|
||||
c.execute('''select * from item''')
|
||||
x = c.fetchall()
|
||||
re = []
|
||||
if x:
|
||||
for i in x:
|
||||
re.append({'item_id': i[0],
|
||||
'type': i[1],
|
||||
'is_available': int2b(i[2])
|
||||
})
|
||||
|
||||
return re
|
||||
|
||||
|
||||
def get_all_purchase():
|
||||
# 所有购买数据查询
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''select * from item''')
|
||||
x = c.fetchall()
|
||||
re = []
|
||||
if x:
|
||||
for i in x:
|
||||
discount_from = None
|
||||
discount_to = None
|
||||
with Connect() as c:
|
||||
c.execute('''select * from purchase''')
|
||||
x = c.fetchall()
|
||||
re = []
|
||||
if x:
|
||||
for i in x:
|
||||
|
||||
if i[5] and i[5] >= 0:
|
||||
discount_from = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[5])/1000))
|
||||
if i[6] and i[6] >= 0:
|
||||
discount_to = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[6])//1000))
|
||||
discount_from = None
|
||||
discount_to = None
|
||||
|
||||
re.append({'item_id': i[0],
|
||||
'type': i[1],
|
||||
'is_available': int2b(i[2]),
|
||||
'price': i[3],
|
||||
'orig_price': i[4],
|
||||
'discount_from': discount_from,
|
||||
'discount_to': discount_to
|
||||
})
|
||||
if i[3] and i[3] >= 0:
|
||||
discount_from = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[3])/1000))
|
||||
if i[4] and i[4] >= 0:
|
||||
discount_to = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[4])//1000))
|
||||
|
||||
c.execute(
|
||||
'''select * from purchase_item where purchase_name=?''', (i[0],))
|
||||
y = c.fetchall()
|
||||
items = []
|
||||
if y:
|
||||
for j in y:
|
||||
items.append({'item_id': j[1], 'type': j[2]})
|
||||
|
||||
re.append({'purchase_name': i[0],
|
||||
'price': i[1],
|
||||
'orig_price': i[2],
|
||||
'discount_from': discount_from,
|
||||
'discount_to': discount_to,
|
||||
'items': items
|
||||
})
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return re
|
||||
|
||||
|
||||
@@ -342,23 +368,27 @@ def update_all_save(c):
|
||||
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
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'''select exists(select * from present where present_id=:a)''', {'a': present_id})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into present values(:a,:b,:c,:d)''', {
|
||||
'a': present_id, 'b': expire_ts, 'c': items, 'd': description})
|
||||
message = '添加成功 Successfully add it.'
|
||||
else:
|
||||
message = '奖励已存在 The present exists.'
|
||||
with Connect() as c:
|
||||
c.execute(
|
||||
'''select exists(select * from present where present_id=:a)''', {'a': present_id})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute(
|
||||
'''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.'
|
||||
else:
|
||||
message = '物品不存在 The item does not exist.'
|
||||
else:
|
||||
message = '奖励已存在 The present exists.'
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return message
|
||||
|
||||
|
||||
@@ -366,21 +396,20 @@ def delete_one_present(present_id):
|
||||
# 删除一个奖励
|
||||
|
||||
message = None
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'''select exists(select * from present where present_id=:a)''', {'a': present_id})
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from present where present_id = :a''',
|
||||
{'a': present_id})
|
||||
c.execute('''delete from user_present where present_id =:a''', {
|
||||
'a': present_id})
|
||||
message = '删除成功 Successfully delete it.'
|
||||
else:
|
||||
message = '奖励不存在 The present does not exist.'
|
||||
with Connect() as c:
|
||||
c.execute(
|
||||
'''select exists(select * from present where present_id=:a)''', {'a': present_id})
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from present where present_id = :a''',
|
||||
{'a': present_id})
|
||||
c.execute('''delete from user_present where present_id =:a''', {
|
||||
'a': present_id})
|
||||
c.execute('''delete from present_item where present_id =:a''', {
|
||||
'a': present_id})
|
||||
message = '删除成功 Successfully delete it.'
|
||||
else:
|
||||
message = '奖励不存在 The present does not exist.'
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return message
|
||||
|
||||
|
||||
@@ -419,45 +448,53 @@ def deliver_all_user_present(c, present_id):
|
||||
return
|
||||
|
||||
|
||||
def add_one_redeem(code, redeem_type, items):
|
||||
def add_one_redeem(code, redeem_type, item_id, item_type, item_amount):
|
||||
# 添加一个兑换码
|
||||
|
||||
message = None
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into redeem values(:a,:b,:c)''', {
|
||||
'a': code, 'b': items, 'c': redeem_type})
|
||||
message = '添加成功 Successfully add it.'
|
||||
else:
|
||||
message = '兑换码已存在 The redeem code exists.'
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return message
|
||||
|
||||
|
||||
def add_some_random_redeem(amount, redeem_type, items):
|
||||
# 随机生成一堆10位的兑换码
|
||||
|
||||
message = None
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
i = 0
|
||||
while i <= amount:
|
||||
code = random_str()
|
||||
with Connect() as c:
|
||||
c.execute(
|
||||
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into redeem values(:a,:b,:c)''',
|
||||
{'a': code, 'b': items, 'c': redeem_type})
|
||||
i += 1
|
||||
c.execute(
|
||||
'''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.'
|
||||
else:
|
||||
message = '物品不存在 The item does not exist.'
|
||||
else:
|
||||
message = '兑换码已存在 The redeem code exists.'
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def add_some_random_redeem(amount, redeem_type, item_id, item_type, item_amount):
|
||||
# 随机生成一堆10位的兑换码
|
||||
|
||||
message = None
|
||||
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
|
||||
while i <= amount:
|
||||
code = random_str()
|
||||
c.execute(
|
||||
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (0,):
|
||||
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))
|
||||
i += 1
|
||||
|
||||
message = '添加成功 Successfully add it.'
|
||||
|
||||
message = '添加成功 Successfully add it.'
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return message
|
||||
|
||||
|
||||
@@ -465,19 +502,19 @@ def delete_one_redeem(code):
|
||||
# 删除一个兑换码
|
||||
|
||||
message = None
|
||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||
c = conn.cursor()
|
||||
c.execute(
|
||||
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from redeem where code = :a''', {'a': code})
|
||||
c.execute('''delete from user_redeem where code =:a''', {'a': code})
|
||||
message = '删除成功 Successfully delete it.'
|
||||
else:
|
||||
message = '兑换码不存在 The redeem code does not exist.'
|
||||
with Connect() as c:
|
||||
c.execute(
|
||||
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||
if c.fetchone() == (1,):
|
||||
c.execute('''delete from redeem where code = :a''', {'a': code})
|
||||
c.execute(
|
||||
'''delete from user_redeem where code =:a''', {'a': code})
|
||||
c.execute(
|
||||
'''delete from redeem_item where code =:a''', {'a': code})
|
||||
message = '删除成功 Successfully delete it.'
|
||||
else:
|
||||
message = '兑换码不存在 The redeem code does not exist.'
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return message
|
||||
|
||||
|
||||
@@ -499,7 +536,7 @@ def ban_one_user(c, user_id):
|
||||
|
||||
def clear_user_score(c, user_id):
|
||||
# 清除用户所有成绩,包括best_score和recent30,以及recent数据,但不包括云端存档
|
||||
c.execute('''update user set rating_ptt=0, song_id='', difficulty=0, score=0, shiny_perfect_count=0, perfect_count=0, near_count=0, miss_count=0, health=0, time_played=0, rating=0 where user_id=:a''',
|
||||
c.execute('''update user set rating_ptt=0, song_id='', difficulty=0, score=0, shiny_perfect_count=0, perfect_count=0, near_count=0, miss_count=0, health=0, time_played=0, rating=0, world_rank_score=0 where user_id=:a''',
|
||||
{'a': user_id})
|
||||
c.execute('''delete from best_score where user_id=:a''', {'a': user_id})
|
||||
c.execute('''delete from recent30 where user_id=:a''', {'a': user_id})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import time
|
||||
|
||||
|
||||
def get_user_score(c, user_id, limit=-1):
|
||||
def get_user_score(c, user_id, limit=-1, offset=0):
|
||||
# 返回用户的所有歌曲数据,带排名,返回字典列表
|
||||
if limit >= 0:
|
||||
c.execute('''select * from best_score where user_id =:a order by rating DESC limit :b''',
|
||||
{'a': user_id, 'b': limit})
|
||||
c.execute('''select * from best_score where user_id =:a order by rating DESC limit :b offset :c''',
|
||||
{'a': user_id, 'b': limit, 'c': offset})
|
||||
else:
|
||||
c.execute(
|
||||
'''select * from best_score where user_id =:a order by rating DESC''', {'a': user_id})
|
||||
@@ -49,6 +49,10 @@ def get_user(c, user_id):
|
||||
if x[20]:
|
||||
time_played = time.strftime('%Y-%m-%d %H:%M:%S',
|
||||
time.localtime(int(x[20])//1000))
|
||||
if x[2] == '':
|
||||
ban_flag = True
|
||||
else:
|
||||
ban_flag = False
|
||||
|
||||
r = {'name': x[1],
|
||||
'user_id': user_id,
|
||||
@@ -65,14 +69,15 @@ def get_user(c, user_id):
|
||||
'time_played': time_played,
|
||||
'clear_type': x[21],
|
||||
'rating': x[22],
|
||||
'ticket': x[26]
|
||||
'ticket': x[26],
|
||||
'ban_flag': ban_flag
|
||||
}
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def get_user_recent30(c, user_id):
|
||||
# 获取玩家recent30信息并计算这一部分的ptt,返回字典列表和一个值
|
||||
# 获取玩家recent30信息并计算recent10的ptt,返回字典列表和一个值
|
||||
c.execute('''select * from recent30 where user_id=:a''', {'a': user_id})
|
||||
sumr = 0
|
||||
x = c.fetchone()
|
||||
|
||||
Reference in New Issue
Block a user