Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87661cf871 | ||
|
|
d6d98aa561 | ||
|
|
2c78e6646a | ||
|
|
0f8010ae8d | ||
|
|
cb5db5e55f | ||
|
|
a99503a86d | ||
|
|
37660a382a | ||
|
|
e43faeff10 | ||
|
|
2189132753 | ||
|
|
85aad3377e | ||
|
|
2f5a63858f | ||
|
|
dbffb15779 | ||
|
|
1f544ddb7e | ||
|
|
7f47315130 | ||
|
|
afe9f27c25 | ||
|
|
f8ca0bdcd3 | ||
|
|
98caa9248b | ||
|
|
0236d44466 | ||
|
|
4c0e933ea4 | ||
|
|
8b284107b1 | ||
|
|
2c31bd0c47 | ||
|
|
7b329bc37c | ||
|
|
0937c0fadf | ||
|
|
ea92e4e981 | ||
|
|
1cfd577f56 | ||
|
|
b7187fe0ed | ||
|
|
60c089a810 | ||
|
|
377096a077 | ||
|
|
87de79ef12 | ||
|
|
f1386f8e3d | ||
|
|
6d581c114d | ||
|
|
9570349565 | ||
|
|
206d12742a | ||
|
|
f2434cef7e | ||
|
|
2474879c89 | ||
|
|
4c36e0abf0 | ||
|
|
ccd5fd72c8 | ||
|
|
46499a5425 | ||
|
|
8562da15b6 | ||
|
|
8195e9f937 | ||
|
|
9f57ff1342 | ||
|
|
a7b7a01685 | ||
|
|
8ada783f7c | ||
|
|
f79c4a4370 | ||
|
|
f3be39823a | ||
|
|
03d0e87b55 | ||
|
|
efcc1caa76 | ||
|
|
2a546c0d9d | ||
|
|
63627eaf78 | ||
|
|
ed7c461fe1 | ||
|
|
75ac6e03f2 | ||
|
|
2f2dc82b5a | ||
|
|
198256e6ff | ||
|
|
eb276128c2 | ||
|
|
6090a60467 | ||
|
|
2099622b0f | ||
|
|
9494f3026b | ||
|
|
f7ceb6bcda | ||
|
|
04dac7279e | ||
|
|
8c164b6130 | ||
|
|
27b229e1c2 | ||
|
|
c877d9d214 | ||
|
|
636789b8bf | ||
|
|
48aeb1c9d2 | ||
|
|
5f09c00eb4 | ||
|
|
bf28710000 | ||
|
|
8c61bda865 | ||
|
|
1fa268e6ba | ||
|
|
4fe69077fc | ||
|
|
4f5eb97309 | ||
|
|
122c397b59 | ||
|
|
d3984dcd5d | ||
|
|
4abc04e9f6 | ||
|
|
c01dbb50f7 | ||
|
|
fa5ed284e1 | ||
|
|
76583f17ce | ||
|
|
f959993197 | ||
|
|
6dceb7c48a | ||
|
|
1869c37949 | ||
|
|
1d8fd582c9 | ||
|
|
9b22318934 | ||
|
|
71a7cd7eed | ||
|
|
6c22c4287e | ||
|
|
a8539b475e | ||
|
|
abcccfb9a0 | ||
|
|
b2288b9b8f | ||
|
|
e61b103221 | ||
|
|
94ed27503a | ||
|
|
ad1b48c210 | ||
|
|
75b35e09e2 | ||
|
|
834804b2ea | ||
|
|
ac9cf50d28 | ||
|
|
cb4743f86f | ||
|
|
cef7e99e46 | ||
|
|
4b007b446d | ||
|
|
4c5122d163 | ||
|
|
01198d546a | ||
|
|
bc5f26d768 | ||
|
|
9a652e1ace | ||
|
|
7b21a0bdae | ||
|
|
5311618d1d | ||
|
|
37ce14dda7 | ||
|
|
0d8d5845c9 | ||
|
|
143f534ba1 | ||
|
|
4db3d94ee8 | ||
|
|
e195cf77cd | ||
|
|
ac9622f1bd | ||
|
|
e8535b1a80 | ||
|
|
d81b763d9b | ||
|
|
1c5726be4c | ||
|
|
6da5abcefc | ||
|
|
c5e39f104f | ||
|
|
60d2f7cfd3 | ||
|
|
0ac8b44ce0 | ||
|
|
59fec74d08 | ||
|
|
52f142a2b9 | ||
|
|
3a7132d276 | ||
|
|
4f89894fd1 | ||
|
|
c50a0093fd | ||
|
|
1b41b82745 | ||
|
|
d1d63e1ef9 | ||
|
|
beb9144e9b | ||
|
|
d58f4bed8f | ||
|
|
125e4d8ca7 | ||
|
|
b096a79f95 | ||
|
|
04b0ccfda3 | ||
|
|
82bd9ad7bb | ||
|
|
6a4ac795b2 | ||
|
|
3a71f5054c | ||
|
|
650e05310d | ||
|
|
3aee0f611c | ||
|
|
fa45169b96 | ||
|
|
07222c9ae9 | ||
|
|
38298a2840 | ||
|
|
2440bedf4a | ||
|
|
9acc375d99 | ||
|
|
799ace06d7 | ||
|
|
6d91659b24 | ||
|
|
151dd41e64 | ||
|
|
13e234a68c | ||
|
|
839debca97 | ||
|
|
abda3d5279 | ||
|
|
44d8c0a824 | ||
|
|
f348feff62 | ||
|
|
6603b6aaa6 | ||
|
|
a96924c24f | ||
|
|
aa53fd8146 | ||
|
|
bbb5a3b408 | ||
|
|
072d70b42a | ||
|
|
f9970fa81c | ||
|
|
30d42bd832 | ||
|
|
3e6b4f4798 | ||
|
|
2ccd9dc382 | ||
|
|
691841187b | ||
|
|
a71a73e324 | ||
|
|
078cb84b35 | ||
|
|
775584a645 | ||
|
|
384212ce2e | ||
|
|
1567b689b9 | ||
|
|
254478e20c | ||
|
|
4dd3f39472 | ||
|
|
49802602bf | ||
|
|
6ab2112ea9 | ||
|
|
6be23145d8 | ||
|
|
cc0cd06c92 | ||
|
|
9697b4b06e | ||
|
|
db260d5f2f | ||
|
|
3f62f1683b | ||
|
|
7118a72b3b | ||
|
|
a5256c97d3 | ||
|
|
84023e2eb8 | ||
|
|
39849483c8 | ||
|
|
490264b35a |
@@ -9,6 +9,9 @@ insert_final_newline = true
|
|||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
max_line_length = 79
|
max_line_length = 79
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
[*.sql]
|
[*.sql]
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -1,6 +1,4 @@
|
|||||||
bin/
|
bin/
|
||||||
|
data/
|
||||||
node_modules/
|
node_modules/
|
||||||
pki/
|
|
||||||
state/
|
|
||||||
.env
|
.env
|
||||||
hostname.txt
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
image: node:12-buster
|
||||||
|
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- node_modules/
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
|
||||||
|
do_build:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- npm install
|
||||||
|
- npm run build
|
||||||
|
- npm test
|
||||||
|
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"mikestead.dotenv"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.rulers": [79],
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v016
|
||||||
|
|
||||||
|
- IDZ: Fix SQL syntax error (Tau)
|
||||||
|
|
||||||
|
## v015
|
||||||
|
|
||||||
|
- IDZ: Team fixes (BemaniWitch)
|
||||||
|
|
||||||
|
## v014
|
||||||
|
|
||||||
|
- IDZ: Add support for Initial D v2.1 (BemaniWitch)
|
||||||
|
|
||||||
|
## v013
|
||||||
|
|
||||||
|
- IDZ: Miscellaneous refactoring (Tau)
|
||||||
|
- Chunithm: Add stubs to support Amazon Plus (Felix)
|
||||||
|
|
||||||
|
## v012
|
||||||
|
|
||||||
|
- Chunithm: Fix large data loads (NeumPhis)
|
||||||
|
- Chunithm: Add some support for older versions (NeumPhis)
|
||||||
|
- Chunithm: Fix large data loads (Felix)
|
||||||
|
- Chunithm: Enable all events (Felix)
|
||||||
|
- Chunithm: Remove server maintenance period (Felix)
|
||||||
|
- Chunithm: Fix data loss (esterTion)
|
||||||
|
- Chunithm: Add some support for older versions (esterTion)
|
||||||
|
- IDZ: Team-related fixes (Emi Midnight)
|
||||||
|
- Add support for newer AIME card services (cxm)
|
||||||
|
- Chunithm: Enable ticket system (Rob)
|
||||||
|
- Chunithm: Implement Recent Rating feature (seika1)
|
||||||
|
- Chunithm: Fix User Activity feature (seika1)
|
||||||
|
|
||||||
|
## v011
|
||||||
|
|
||||||
|
- IDZ: Fix loading of >10 cars in garage (Tau)
|
||||||
|
|
||||||
|
## v010
|
||||||
|
|
||||||
|
- Chunithm: Bug fix: Fix new database creation and repair affected databases. Again. (Tau)
|
||||||
|
Switch to a different SQLite native code extension. C compiler is no longer required. (Tau)
|
||||||
|
|
||||||
|
## v009
|
||||||
|
|
||||||
|
- IDZ: Display team banners in attract loop rankings (Tau)
|
||||||
|
- Chunithm: Bug fix: Fix new database creation and repair affected databases (Tau)
|
||||||
|
|
||||||
|
## v008
|
||||||
|
|
||||||
|
- Implement auras in IDZ (BemaniWitch)
|
||||||
|
- Fix user ratings (NeumPhis)
|
||||||
|
- Load and save course results (NeumPhis)
|
||||||
|
- Load and save user duel list (Felix)
|
||||||
|
|
||||||
|
## v007
|
||||||
|
|
||||||
|
- Fix IDZ team creation (Tau)
|
||||||
|
- Fix startup script working directory (Tau)
|
||||||
|
|
||||||
|
## v006
|
||||||
|
|
||||||
|
- Fix Chunithm HTTP POST size limit (Tau)
|
||||||
|
|
||||||
|
## v005
|
||||||
|
|
||||||
|
- Initial public release (Tau)
|
||||||
|
- Chunithm v1.30.00 Amazon
|
||||||
|
- Initial D Zero v1.21.00
|
||||||
|
- Initial D Zero v1.31.00
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# MiniMe
|
||||||
|
|
||||||
|
A simple self-hosted ALLNET/AiMe server written in TypeScript, running on Node.js, that stores its data in an SQLite database.
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This shell script documents the process that was used to generate our fake
|
||||||
|
# P-Ras PKI. It should not need to be run again under normal circumstances.
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
D=`dirname $0`
|
D=`dirname $0`
|
||||||
|
|||||||
Generated
+7796
File diff suppressed because it is too large
Load Diff
+21
-16
@@ -1,49 +1,54 @@
|
|||||||
{
|
{
|
||||||
"name": "knuckles",
|
"name": "minime",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Test server",
|
"description": "Test server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@decafcode/sqlite": "^2.0.0",
|
||||||
"compression": "^1.7.3",
|
"compression": "^1.7.3",
|
||||||
"date-fns": "^1.30.1",
|
"date-fns": "^1.30.1",
|
||||||
|
"debug": "^4.1.1",
|
||||||
"dotenv": "^7.0.0",
|
"dotenv": "^7.0.0",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"iconv-lite": "^0.4.24",
|
"iconv-lite": "^0.4.24",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.9.1",
|
||||||
"multiparty": "^4.2.1",
|
"multiparty": "^4.2.1",
|
||||||
"pg": "^7.10.0",
|
|
||||||
"raw-body": "^2.3.3",
|
"raw-body": "^2.3.3",
|
||||||
"sql-bricks-postgres": "^0.5.0"
|
"snake-case": "^2.1.0",
|
||||||
},
|
"sql-bricks-postgres": "^0.5.0",
|
||||||
"scripts": {
|
"supports-color": "^7.1.0"
|
||||||
"build": "tsc",
|
|
||||||
"test": "jest",
|
|
||||||
"start": "ts-node src/index.ts"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/compression": "^0.0.36",
|
"@types/compression": "^0.0.36",
|
||||||
|
"@types/debug": "^4.1.5",
|
||||||
"@types/dotenv": "^6.1.1",
|
"@types/dotenv": "^6.1.1",
|
||||||
"@types/express": "^4.16.1",
|
"@types/express": "^4.16.1",
|
||||||
"@types/jest": "^24.0.11",
|
"@types/jest": "^24.0.11",
|
||||||
"@types/multiparty": "^0.0.32",
|
"@types/multiparty": "^0.0.32",
|
||||||
"@types/node": "^11.11.3",
|
"@types/node": "^12.11.7",
|
||||||
"@types/pg": "^7.4.14",
|
"jest": "^26.4.2",
|
||||||
"@types/sql-bricks": "^2.0.1",
|
"jest-haste-map": "^26.3.0",
|
||||||
"jest": "^24.5.0",
|
|
||||||
"jest-haste-map": "^24.5.0",
|
|
||||||
"jest-resolve": "^24.5.0",
|
"jest-resolve": "^24.5.0",
|
||||||
"prettier": "^1.16.4",
|
"prettier": "^1.16.4",
|
||||||
"ts-jest": "^24.0.0",
|
"ts-jest": "^26.3.0",
|
||||||
"ts-node": "^8.0.3",
|
"typescript": "^3.8.3",
|
||||||
"typescript": "^3.3.3333",
|
|
||||||
"utility-types": "^3.6.1"
|
"utility-types": "^3.6.1"
|
||||||
},
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"prepare": "tsc",
|
||||||
|
"test": "jest",
|
||||||
|
"watch": "tsc --watch"
|
||||||
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"preset": "ts-jest",
|
"preset": "ts-jest",
|
||||||
"testEnvironment": "node"
|
"testEnvironment": "node"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "es5"
|
"trailingComma": "es5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAML2GPUuzv2N4bYC
|
||||||
|
xtc5bZSzolHFWdCUbP+whjr3K98FOLnYeoi7mtUSUUYOW8wIqy6WM3c4c0Bp7FcQ
|
||||||
|
LnZ0zWMm1TfLGHZzZmk5n7Iv6HDPr3ehDgbWLnOpRrVqZDxpAGD2vQb4p2DW4I2x
|
||||||
|
GUqnqDa++C8dH/0lXqE6cqwGXNGtAgMBAAECgYEAizgPhG4Dk55QkpeTBDfXH3vT
|
||||||
|
Ko9B3qdO2ptkjxDX/C8PXe7POXq2SvcEoIE6Xg3Gp8LMR5NBAbth8J32f9JSov3P
|
||||||
|
SiGCGno4k2i2s3jRuVg76FGLDsZH/N1dt4h78VnW0VlInwaM6bQv3zp0u8rXVk/P
|
||||||
|
wpYh9AGmquBJS3VYUcECQQD0PDRe28SrhollygGZSO321rYbYhoTIstDXZWyQ/y/
|
||||||
|
PWKNwNHcYTHIVGmTrJx2AJUyr1tJhwjiOwlsI5Y1Q4/9AkEAzFpFPcs1r/xgSFxB
|
||||||
|
eYrcNseWYbVajtVxG9t57sayaEQbH2UMNA2vqSYK/nU6oJhj5eLRIsPHlA5ZbIiZ
|
||||||
|
rvc/cQJAKS0RQ0DX+ncXKQMSm+4wuGHgl+NFNB60mCnp+AEAVpmZyP5OI1J7myOo
|
||||||
|
HQ6H3lkgzkfEIzRR6ho773BcfaRjXQJAfS4nEE11G9ML4AezjBLGB0CIHF6NlMWn
|
||||||
|
PhtaPCy3iSt/OeIacaCYpJNLVMjXGx1+xIoG9rbbgRSxLs0W55lJ4QJBALOUVcNw
|
||||||
|
GKEJdxhIkA8iuUlEyGpKluAgHUNOOKvC3ogRoB0OyH+If/9o8wWDfxgexgM0zGBc
|
||||||
|
u178W9XDW+IijDA=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
Binary file not shown.
BIN
Binary file not shown.
+28
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDeHEJ2L+FXrcdW
|
||||||
|
G8LNZ/WknTzE9lsB4I1Gb7LcrXi/Yq+rEnF8iru2h4j1icmDSuwLBS//qENO2LfE
|
||||||
|
+iU1zmtlhjAfGv8SYSXg1ssAbB6Sv4vvz0U0pNCAvnJ/K8UN7kAXHB1rw5dRvO47
|
||||||
|
A+M1NO8S6pYTL5jJhK+BaNVmP6w9eOQ4c+0ZvKFOEX0E/uy1qcUuS386ZcPFRxRF
|
||||||
|
vErUo8WjyMAwV9HZoVa3h3tAywKfDrYjF8DtdNG93G3igzpv4Iro4AuESrPE3t4x
|
||||||
|
5uiO4UxwUObolkVsmOAzo7g1QiEi0wlHTQX1ZH3dXgaRAF5vv/V02ZAnmI5keXfP
|
||||||
|
DDIqURf3AgMBAAECggEAHQD3tNM/y+FHfHkXkRcYPqzBuL6q163pBN+lLagBcoyC
|
||||||
|
gAZih27eYFGGkvmxNNHdzPqab/oa//rQ1IoNvd78qz9AnW87C71f4uJpk96Kh4M3
|
||||||
|
1NLuKJe1GnrEHNMsYktQVzQ2q1HZOrU/LrmtO89zwLadblfyza3j9TQpWbbK2SPn
|
||||||
|
zVFlBZazX5s5APHgI9PymjPkwC9jsUbSrpe816W9KT8n8cG/CdS7relOXic5PWVL
|
||||||
|
zgWQdCFMhY/aHFbLWM7RIkQTdX0GopJWgleLQqryKHIVu6Vekyrp/eOpl22wzjku
|
||||||
|
DMWEK9ZWLHYejbCZJJIRKxSsxRlwAX2D/9kQ9vs2YQKBgQD/UYGD7ovAjTclJzyx
|
||||||
|
d6dj/C0fHwyFnF+Lknll7AhA1hBYzQ2uaqBSUc2oV19dsxfZfy/tD0gP2ZVSFl1f
|
||||||
|
iF3ON0xVbbb4r3Drck17c5iQ2+z5PHfOHSD3+AwF+stkKwLiJxIudJJppm1Cn6wc
|
||||||
|
WiysnqeEhsaklOe0PvdA8BIkDwKBgQDetA7g2m7FKfODHb9Tx7qDtiRjsbCYD1fF
|
||||||
|
UpF2yQ+twXJAO9AgkxYmmWMQ9/h+yxpsTjE4oDOO5K907x6gGzJFfFrDn0R0zIfw
|
||||||
|
0EobfwJ4l28rqUYvQzgYyc/UW2PiuLIr2otXQNmtOnYmPogLIMlgQSvEnseXCs//
|
||||||
|
0+TRKKbFmQKBgGVJYVcEeF6P5xOPKE3DCR3qOcBB4gbTTTgiiJR9eZy3D08bMdVC
|
||||||
|
qY1etHaXCtcyKED5avrheBYJnGovQyWWBJi9aUPuvYqUlvhgpQpXhmvZQ35wlZqo
|
||||||
|
BZ85wRNSNgPr6D3tgBH73uWYx3mJvI6W22gznIM/sGg0RmNEI3SYiKnTAoGAJ1mx
|
||||||
|
d1GhWP08peJPuEIGVteMPoFbLsMnQxp/0XldZ9pSkb7/24Gh3FgmBQ2LvvusQ47d
|
||||||
|
a6AC/DC0P/kwdCHaFCUQ9JfjxK+PJaHoNkuO6Df50MEsQZWjB95A9sjfMWRpNw56
|
||||||
|
qIQw8kbuMXvDFhRJANUDIs7bfXjPn+iU+dAxB6ECgYEAusdd0y30VXE9Mj6zJ2Ee
|
||||||
|
Cm1L9THijgcPH/Q7rD9Vk5yPSXuKO9Q2atgY0COOeQxwmwjf8UHYldDxLjor1nz0
|
||||||
|
CdwQihCexJSXuoQ9LA/XeTLDm/F/M1Eze+MgOE23dT9qEUOwHrjDsyuYwfev7ir9
|
||||||
|
a11MWJKcdkeKS/lGXeX3MbE=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDLTCCAhWgAwIBAgIUQ67cF8bq3m9pcWq6zJeZRc8N60EwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwJTEQMA4GA1UEAwwHRHVtbXlDQTERMA8GA1UECgwIRHVtbXlQS0kwIBcNMTgx
|
||||||
|
MDE1MTkzMDUxWhgPMjExODEwMTUxOTMwNTFaMCUxEDAOBgNVBAMMB0R1bW15Q0Ex
|
||||||
|
ETAPBgNVBAoMCER1bW15UEtJMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||||
|
AQEA3hxCdi/hV63HVhvCzWf1pJ08xPZbAeCNRm+y3K14v2KvqxJxfIq7toeI9YnJ
|
||||||
|
g0rsCwUv/6hDTti3xPolNc5rZYYwHxr/EmEl4NbLAGwekr+L789FNKTQgL5yfyvF
|
||||||
|
De5AFxwda8OXUbzuOwPjNTTvEuqWEy+YyYSvgWjVZj+sPXjkOHPtGbyhThF9BP7s
|
||||||
|
tanFLkt/OmXDxUcURbxK1KPFo8jAMFfR2aFWt4d7QMsCnw62IxfA7XTRvdxt4oM6
|
||||||
|
b+CK6OALhEqzxN7eMebojuFMcFDm6JZFbJjgM6O4NUIhItMJR00F9WR93V4GkQBe
|
||||||
|
b7/1dNmQJ5iOZHl3zwwyKlEX9wIDAQABo1MwUTAdBgNVHQ4EFgQUxHdbXQ7dqFqw
|
||||||
|
jzzl02L+UefEwNgwHwYDVR0jBBgwFoAUxHdbXQ7dqFqwjzzl02L+UefEwNgwDwYD
|
||||||
|
VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEApcWGs+A06Aaqr9VAxhDp
|
||||||
|
i4vSV0K++912IJWRv6rRRy7Hz4b7Ov5UOZ7AHshnQNWQvd9Qp+ehhNoLjL5joWk9
|
||||||
|
BmwMPGAPhBAvidDh8QULUAIDJWDGF8CtDDaW8oHYjsBTBSVjKu1Ma/OVMc9vF0Ej
|
||||||
|
MUb3LtlKZkNUqmUCjlE/V2bYYjqVLNTogrXO4KxXyqfBFdUzTCB/qX7V+HNnszDq
|
||||||
|
IFHF+wyTklMSOwTUIrvW4R6zojXL0wjRdvtBqXSvPFq5HWJPdg0dfVyyVDZu7yPO
|
||||||
|
3gMJLqkDkHsaYLs2IKHUXqJCbHCJ/whpMWNYYozDFGrhetNSvo3sKht9wvQK08mc
|
||||||
|
yg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDg1xvj8JLt4nDq
|
||||||
|
rRQOGzCys0bD2VdGRnQ/TYC3ezg0whYbQRD7bUdkNQm1KeNOlj8yr8kjz30swIY6
|
||||||
|
6Ufw82qGH0QjsmbSOTLr13B9K1ogd11aMxErvVnxtNBOkuwtzKL+Zb1D99jvxX0u
|
||||||
|
e0dIsBcuojemyoz6iNbU7WSNtbIFeQFr+MlZujHIv0Hj76MYyZAqNq2F3Ou1SduV
|
||||||
|
kw+Acol8KzTfiII38ibZcP+INgK6YvnrJrxbDZ+NXwsXOeg0y/vZ7hc2h1k5wT3E
|
||||||
|
xWoyMD/bvnVrKTneQfwOI9s4s3pB6o1hGeUGRhPvpJ20+FGOE8LIRzBEixDKl82T
|
||||||
|
G63DVoMJAgMBAAECggEBANKVBf0+BA8jZ4iUpFT16G1mdZ/W/uPF9viXGThAAwt+
|
||||||
|
wH+0ODiUSCo1dqsj2U5wcC6D74pHukBg7RdeCFBHW3zU6dfZLm40vlmfRS8mnFoO
|
||||||
|
EfP6IlnqFcTJCdSdzPC0WfCUz2hKSPeA61bOhZwxuPSnYCIqUVIROczhrqz/AQYX
|
||||||
|
ZuuY7ut0h6X11xoddeeTOdfd+rktxPVpHeJDcz9F6Gk/0pg1ezs66TZ5sWt0/ZhP
|
||||||
|
ZWTB40KPec2lomRGwY36AMOT3uFucnbtJgxhTGdqsRv7Kl0xCTo7xW/85Za7rhXK
|
||||||
|
+xRdHrYr9w6xYTKHi9Ap4HEmUcx/fGAtddxr0fzdpIECgYEA8nRyYYHMdSr4WI/E
|
||||||
|
fD/cpIjKLxw9BCdoXhruVSKp1GmhyQTH7Y0zJQ0uvG7GlsEXJ2V9yqTofzWev8iQ
|
||||||
|
vVzX+14yTKaNUAwc7HCEXMN+xqnq61Bjldx6U54CfdInOhTFuoq8CXu80cHobYMs
|
||||||
|
8SjnYuhp5NqABGR+9YTYaHzjBhkCgYEA7Wa9orxkWruXUdROUZrdhlU44ilxvA66
|
||||||
|
r1vVVLQFNVle2hbie3b93ZQCZrZL8iFsGKOIhXSncQ6pl9GQqDLJvMUiffzUci6G
|
||||||
|
A4GgGlzXpkj+RmAkIkGYafmQqTZhMHNws35LMYoIabn0l8cWwG0XL1pO2YSjaoYg
|
||||||
|
5Kj0TjoNonECgYAcAk3Qa+FFy+ACwyEMxYfkzhSlWprF5xOMg4ny9d0ut8FD6rR6
|
||||||
|
Aezdo+c5R4bTlZzqJTRh+6kMQRKEz1PBPH+K/3fKGReMHsocmmcAHGmB49FKu++1
|
||||||
|
OVI8ZK2fAW8cq5eoFCzi35ORm9gRBq1jcrlAWN8a3A8b8swj6uPhNkQ3yQKBgCH+
|
||||||
|
HBk5MIVtZvVomO5GZoHdog+AL7DlywVg+OLwA+7npRVFQZi8KQ2ZK97ZK3a4ImpE
|
||||||
|
wD+bvH4Lw2zhrPzoiMpmz9GKakEPOFE4NlyP/rDossAQ9BuTmOdTvMr95lyxqumI
|
||||||
|
o+usABhjcAprj25uMGuvWqr6uwt9uSgEqTaqSVmBAoGAMs6/59L8EABC/CkBLp0t
|
||||||
|
y3sYzjyjZr6gnMCkIi95b2FWyIVjlK53dwjKYg67BUI8qLNbUW1NPhyotc/9GklP
|
||||||
|
qiNTkUeKcHOlZqOzP0zPquFk2lSfJuuGrMgElZPcEFLsAWRqnjRGp5iP05nk5OQh
|
||||||
|
foY7svzPedFk/t3eFcOyrPo=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICtDCCAZwCAQAwDQYJKoZIhvcNAQELBQAwJTEQMA4GA1UEAwwHRHVtbXlDQTER
|
||||||
|
MA8GA1UECgwIRHVtbXlQS0kwIBcNMTgxMDE1MTkzMDUxWhgPMjExODEwMTUxOTMw
|
||||||
|
NTFaMBkxFzAVBgNVBAMMDmliLm5hb21pbmV0LmpwMIIBIjANBgkqhkiG9w0BAQEF
|
||||||
|
AAOCAQ8AMIIBCgKCAQEA4Ncb4/CS7eJw6q0UDhswsrNGw9lXRkZ0P02At3s4NMIW
|
||||||
|
G0EQ+21HZDUJtSnjTpY/Mq/JI899LMCGOulH8PNqhh9EI7Jm0jky69dwfStaIHdd
|
||||||
|
WjMRK71Z8bTQTpLsLcyi/mW9Q/fY78V9LntHSLAXLqI3psqM+ojW1O1kjbWyBXkB
|
||||||
|
a/jJWboxyL9B4++jGMmQKjathdzrtUnblZMPgHKJfCs034iCN/Im2XD/iDYCumL5
|
||||||
|
6ya8Ww2fjV8LFznoNMv72e4XNodZOcE9xMVqMjA/2751ayk53kH8DiPbOLN6QeqN
|
||||||
|
YRnlBkYT76SdtPhRjhPCyEcwRIsQypfNkxutw1aDCQIDAQABMA0GCSqGSIb3DQEB
|
||||||
|
CwUAA4IBAQANOqFqjnGf80vvwYEkUsfOWp8rNVat+8rdXl0BShGBXiDItzMOU79K
|
||||||
|
YkPObniQ5RLBMhrvqlCsSk0Np+ZgvV12J4Wtmf/znLa5ZKyeI4N1FCefU9cl4xpB
|
||||||
|
08Fv8YWbYV7SMNr54ZkURdho4FVR1pAnpuittpAEjMT4R4ubbOH8UEbMTbVgxXdn
|
||||||
|
086IAlfsYn0gnOlf76RkJFLe4UlWaZB75SaaXnNavBPN9iFnqXLckg6tsFUJnNMC
|
||||||
|
esq5aHQ9sXWs4oKpJi8SXxt/zNRmgTnQK2ONM38NeZpLmlWPkyNxzsRNlYWo+kWP
|
||||||
|
C98jVFe1+3K88ISk0DSN4XOQQnrIvn68
|
||||||
|
-----END CERTIFICATE-----
|
||||||
+5
-41
@@ -1,45 +1,9 @@
|
|||||||
create schema "aime";
|
create table "aime_player" (
|
||||||
|
"id" integer primary key not null,
|
||||||
create type "aime"."region" as enum (
|
|
||||||
'JPN',
|
|
||||||
'HKG',
|
|
||||||
'SGP',
|
|
||||||
'KOR',
|
|
||||||
'USA'
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "aime"."shop" (
|
|
||||||
"id" bigint primary key not null,
|
|
||||||
"ext_id" integer not null,
|
"ext_id" integer not null,
|
||||||
"name" text not null,
|
"luid" text not null,
|
||||||
"region" "aime"."region" not null,
|
|
||||||
constraint "shop_uq" unique ("ext_id")
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "aime"."machine" (
|
|
||||||
"id" bigint primary key not null,
|
|
||||||
"shop_id" bigint not null
|
|
||||||
references "aime"."shop"("id"),
|
|
||||||
"pcb_id" text not null,
|
|
||||||
"keychip_id" text not null,
|
|
||||||
constraint "machine_pcb_id_uq" unique ("pcb_id"),
|
|
||||||
constraint "machine_keychip_id_uq" unique ("keychip_id")
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "aime"."player" (
|
|
||||||
"id" bigint primary key not null,
|
|
||||||
"ext_id" integer not null,
|
|
||||||
"register_time" timestamp not null,
|
|
||||||
constraint "player_uq" unique ("ext_id")
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "aime"."card" (
|
|
||||||
"id" bigint primary key not null,
|
|
||||||
"player_id" bigint not null
|
|
||||||
references "aime"."player"("id")
|
|
||||||
on delete cascade,
|
|
||||||
"nfc_id" text not null,
|
|
||||||
"register_time" timestamp not null,
|
"register_time" timestamp not null,
|
||||||
"access_time" timestamp not null,
|
"access_time" timestamp not null,
|
||||||
constraint "card_uq" unique ("nfc_id")
|
constraint "aime_player_ext_id_uq" unique ("ext_id"),
|
||||||
|
constraint "aime_player_luid_uq" unique ("luid")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,372 @@
|
|||||||
|
-- SQLite's ALTER TABLE statement is almost useless, and who knows how much of
|
||||||
|
-- this stuff is present in older versions. So while ideally we'd mark a lot
|
||||||
|
-- of these columns NOT NULL that might come back to bite us as we extend
|
||||||
|
-- support downward from Chunithm 4 to Chunithm 1.
|
||||||
|
|
||||||
|
create table "cm_user_data" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
-- Could in theory do a shared primary key with aime_player, since this
|
||||||
|
-- is going to be a 1:1 relation for the foreseeable future, but again
|
||||||
|
-- the SQLite strait-jacket forces us to design defensively.
|
||||||
|
"player_id" integer not null
|
||||||
|
references "aime_player"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"access_code" text,
|
||||||
|
"user_name" text,
|
||||||
|
"is_web_join" text,
|
||||||
|
"web_limit_date" text,
|
||||||
|
"level" integer,
|
||||||
|
"reincarnation_num" integer,
|
||||||
|
"exp" integer,
|
||||||
|
"point" integer,
|
||||||
|
"total_point" integer,
|
||||||
|
"play_count" integer,
|
||||||
|
"multi_play_count" integer,
|
||||||
|
"multi_win_count" integer,
|
||||||
|
"request_res_count" integer,
|
||||||
|
"accept_res_count" integer,
|
||||||
|
"success_res_count" integer,
|
||||||
|
"player_rating" integer,
|
||||||
|
"highest_rating" integer,
|
||||||
|
"nameplate_id" integer,
|
||||||
|
"frame_id" integer,
|
||||||
|
"character_id" integer,
|
||||||
|
"trophy_id" integer,
|
||||||
|
"played_tutorial_bit" integer,
|
||||||
|
"first_tutorial_cancel_num" integer,
|
||||||
|
"master_tutorial_cancel_num" integer,
|
||||||
|
"total_repertoire_count" integer,
|
||||||
|
"total_map_num" integer,
|
||||||
|
"total_hi_score" integer,
|
||||||
|
"total_basic_high_score" integer,
|
||||||
|
"total_advanced_high_score" integer,
|
||||||
|
"total_expert_high_score" integer,
|
||||||
|
"total_master_high_score" integer,
|
||||||
|
"event_watched_date" text,
|
||||||
|
"friend_count" integer,
|
||||||
|
"is_maimai" text,
|
||||||
|
"first_game_id" text,
|
||||||
|
"first_rom_version" text,
|
||||||
|
"first_data_version" text,
|
||||||
|
"first_play_date" text,
|
||||||
|
"last_game_id" text,
|
||||||
|
"last_rom_version" text,
|
||||||
|
"last_data_version" text,
|
||||||
|
"last_play_date" text,
|
||||||
|
"last_place_id" integer,
|
||||||
|
"last_place_name" text,
|
||||||
|
"last_region_id" text,
|
||||||
|
"last_region_name" text,
|
||||||
|
"last_all_net_id" text,
|
||||||
|
"last_client_id" text
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_activity" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"kind" integer not null,
|
||||||
|
-- This is just called "id" on the wire but, well, we already have an "id"
|
||||||
|
-- column up there ^
|
||||||
|
"activity_id" integer not null,
|
||||||
|
"sort_number" integer not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
constraint "cm_user_activity_uq" unique (
|
||||||
|
"profile_id",
|
||||||
|
"kind",
|
||||||
|
"activity_id"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_charge" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"charge_id" integer not null,
|
||||||
|
"stock" integer not null,
|
||||||
|
"purchase_date" text not null,
|
||||||
|
"valid_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param_date" text not null,
|
||||||
|
constraint "cm_user_charge_uq" unique ("profile_id", "charge_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_course" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"course_id" integer not null,
|
||||||
|
"class_id" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"score_max" integer not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_success" text not null,
|
||||||
|
"score_rank" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"last_play_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
constraint "cm_user_course_uq" unique ("profile_id", "course_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_data_ex" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"compatible_cm_version" text not null,
|
||||||
|
"medal" integer not null,
|
||||||
|
"map_icon_id" integer not null,
|
||||||
|
"voice_id" integer not null,
|
||||||
|
"ext1" integer not null,
|
||||||
|
"ext2" integer not null,
|
||||||
|
"ext3" integer not null,
|
||||||
|
"ext4" integer not null,
|
||||||
|
"ext5" integer not null,
|
||||||
|
"ext6" integer not null,
|
||||||
|
"ext7" integer not null,
|
||||||
|
"ext8" integer not null,
|
||||||
|
"ext9" integer not null,
|
||||||
|
"ext10" integer not null,
|
||||||
|
"ext11" integer not null,
|
||||||
|
"ext12" integer not null,
|
||||||
|
"ext13" integer not null,
|
||||||
|
"ext14" integer not null,
|
||||||
|
"ext15" integer not null,
|
||||||
|
"ext16" integer not null,
|
||||||
|
"ext17" integer not null,
|
||||||
|
"ext18" integer not null,
|
||||||
|
"ext19" integer not null,
|
||||||
|
"ext20" integer not null,
|
||||||
|
"ext_str1" text not null,
|
||||||
|
"ext_str2" text not null,
|
||||||
|
"ext_str3" text not null,
|
||||||
|
"ext_str4" text not null,
|
||||||
|
"ext_str5" text not null,
|
||||||
|
"ext_long1" integer not null,
|
||||||
|
"ext_long2" integer not null,
|
||||||
|
"ext_long3" integer not null,
|
||||||
|
"ext_long4" integer not null,
|
||||||
|
"ext_long5" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_duel_list" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"duel_id" integer not null,
|
||||||
|
"progress" integer not null,
|
||||||
|
"point" integer not null,
|
||||||
|
"is_clear" boolean not null,
|
||||||
|
"last_play_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
constraint "cm_user_duel_list_uq" unique ("profile_id", "duel_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_character" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"character_id" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"level" integer not null,
|
||||||
|
"skill_id" integer not null,
|
||||||
|
"friendship_exp" integer not null,
|
||||||
|
"is_valid" integer not null,
|
||||||
|
"is_new_mark" integer not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
constraint "cm_user_character_uq" unique ("profile_id", "character_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_game_option" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"bg_info" integer not null,
|
||||||
|
"field_color" integer not null,
|
||||||
|
"guide_sound" integer not null,
|
||||||
|
"sound_effect" integer not null,
|
||||||
|
"guide_line" integer not null,
|
||||||
|
"speed" integer not null,
|
||||||
|
"option_set" integer not null,
|
||||||
|
"matching" integer not null,
|
||||||
|
"judge_pos" integer not null,
|
||||||
|
"rating" integer not null,
|
||||||
|
"judge_justice" integer not null,
|
||||||
|
"judge_attack" integer not null,
|
||||||
|
"headphone" integer not null,
|
||||||
|
"player_level" integer not null,
|
||||||
|
"success_tap" integer not null,
|
||||||
|
"success_ex_tap" integer not null,
|
||||||
|
"success_slide_hold" integer not null,
|
||||||
|
"success_air" integer not null,
|
||||||
|
"success_flick" integer not null,
|
||||||
|
"success_skill" integer not null,
|
||||||
|
"success_tap_timbre" integer not null,
|
||||||
|
"privacy" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_game_option_ex" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"ext1" integer not null,
|
||||||
|
"ext2" integer not null,
|
||||||
|
"ext3" integer not null,
|
||||||
|
"ext4" integer not null,
|
||||||
|
"ext5" integer not null,
|
||||||
|
"ext6" integer not null,
|
||||||
|
"ext7" integer not null,
|
||||||
|
"ext8" integer not null,
|
||||||
|
"ext9" integer not null,
|
||||||
|
"ext10" integer not null,
|
||||||
|
"ext11" integer not null,
|
||||||
|
"ext12" integer not null,
|
||||||
|
"ext13" integer not null,
|
||||||
|
"ext14" integer not null,
|
||||||
|
"ext15" integer not null,
|
||||||
|
"ext16" integer not null,
|
||||||
|
"ext17" integer not null,
|
||||||
|
"ext18" integer not null,
|
||||||
|
"ext19" integer not null,
|
||||||
|
"ext20" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_item" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"item_kind" integer not null,
|
||||||
|
"item_id" integer not null,
|
||||||
|
"stock" integer not null,
|
||||||
|
"is_valid" text not null,
|
||||||
|
constraint "cm_user_item_uq" unique ("profile_id", "item_kind", "item_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_map" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"map_id" integer not null,
|
||||||
|
"position" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
"area_id" integer not null,
|
||||||
|
"route_number" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"rate" integer not null,
|
||||||
|
"status_count" integer not null,
|
||||||
|
"is_valid" text not null,
|
||||||
|
constraint "cm_user_map_uq" unique ("profile_id", "map_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_music" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"music_id" integer not null,
|
||||||
|
"level" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"score_max" integer not null,
|
||||||
|
"res_request_count" integer not null,
|
||||||
|
"res_accept_count" integer not null,
|
||||||
|
"res_success_count" integer not null,
|
||||||
|
"miss_count" integer not null,
|
||||||
|
"max_combo_count" integer not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_success" text not null,
|
||||||
|
"full_chain" integer not null,
|
||||||
|
"max_chain" integer not null,
|
||||||
|
"score_rank" integer not null,
|
||||||
|
"is_lock" text not null,
|
||||||
|
constraint "cm_user_music_uq" unique ("profile_id", "music_id", "level")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_playlog" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"order_id" integer not null,
|
||||||
|
"sort_number" integer not null,
|
||||||
|
"place_id" integer not null,
|
||||||
|
"play_date" text not null,
|
||||||
|
"user_play_date" text not null,
|
||||||
|
"music_id" integer not null,
|
||||||
|
"level" integer not null,
|
||||||
|
"custom_id" integer not null,
|
||||||
|
"played_user_id1" integer not null,
|
||||||
|
"played_user_id2" integer not null,
|
||||||
|
"played_user_id3" integer not null,
|
||||||
|
"played_user_name1" text not null,
|
||||||
|
"played_user_name2" text not null,
|
||||||
|
"played_user_name3" text not null,
|
||||||
|
"played_music_level1" integer not null,
|
||||||
|
"played_music_level2" integer not null,
|
||||||
|
"played_music_level3" integer not null,
|
||||||
|
"played_custom1" integer not null,
|
||||||
|
"played_custom2" integer not null,
|
||||||
|
"played_custom3" integer not null,
|
||||||
|
"track" integer not null,
|
||||||
|
"score" integer not null,
|
||||||
|
"rank" integer not null,
|
||||||
|
"max_combo" integer not null,
|
||||||
|
"max_chain" integer not null,
|
||||||
|
"rate_tap" integer not null,
|
||||||
|
"rate_hold" integer not null,
|
||||||
|
"rate_slide" integer not null,
|
||||||
|
"rate_air" integer not null,
|
||||||
|
"rate_flick" integer not null,
|
||||||
|
"judge_guilty" integer not null,
|
||||||
|
"judge_attack" integer not null,
|
||||||
|
"judge_justice" integer not null,
|
||||||
|
"judge_critical" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"player_rating" integer not null,
|
||||||
|
"is_new_record" text not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"full_chain_kind" integer not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_continue" text not null,
|
||||||
|
"is_free_to_play" text not null,
|
||||||
|
"character_id" integer not null,
|
||||||
|
"skill_id" integer not null,
|
||||||
|
"play_kind" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
"skill_level" integer not null,
|
||||||
|
"skill_effect" integer not null,
|
||||||
|
"place_name" text not null,
|
||||||
|
"is_maimai" text not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_recent_rating" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"sort_order" integer not null,
|
||||||
|
"music_id" integer not null,
|
||||||
|
"difficult_id" integer not null,
|
||||||
|
"rom_version_code" integer not null,
|
||||||
|
"score" integer not null,
|
||||||
|
constraint "cm_user_recent_rating_uq" unique ("profile_id", "sort_order")
|
||||||
|
);
|
||||||
+180
-134
@@ -2,129 +2,159 @@
|
|||||||
-- A "course" contains an uphill and downhill "route"
|
-- A "course" contains an uphill and downhill "route"
|
||||||
-- (or inbound/outbound etc)
|
-- (or inbound/outbound etc)
|
||||||
|
|
||||||
create schema "idz";
|
create table "idz_profile" (
|
||||||
|
"id" integer primary key not null,
|
||||||
create type "idz"."gender" as enum ('male', 'female');
|
"player_id" integer not null
|
||||||
|
references "aime_player"("id")
|
||||||
create table "idz"."profile" (
|
|
||||||
"id" bigint primary key not null,
|
|
||||||
"player_id" bigint not null
|
|
||||||
references "aime"."player"("id")
|
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
|
-- Major version of Initial D Zero, either 1 or 2.
|
||||||
|
-- The two major versions are incompatible with each other and do not
|
||||||
|
-- permit the player to carry progress over from one to the other.
|
||||||
|
"version" integer not null,
|
||||||
-- TODO shop_id
|
-- TODO shop_id
|
||||||
"name" text not null,
|
"name" text not null,
|
||||||
"lv" smallint not null,
|
"lv" integer not null,
|
||||||
"exp" integer not null,
|
"exp" integer not null,
|
||||||
"fame" integer not null,
|
"fame" integer not null,
|
||||||
"dpoint" integer not null,
|
"dpoint" integer not null,
|
||||||
"mileage" integer not null,
|
"mileage" integer not null,
|
||||||
"register_time" timestamp not null,
|
"register_time" timestamp not null,
|
||||||
"access_time" timestamp not null,
|
"access_time" timestamp not null,
|
||||||
constraint "profile_player_uq" unique ("player_id")
|
constraint "idz_profile_player_uq" unique ("player_id", "version")
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."chara" (
|
create table "idz_chara" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"gender" "idz"."gender" not null,
|
"gender" text not null,
|
||||||
"field_02" integer not null,
|
"field_02" integer not null,
|
||||||
"field_04" integer not null,
|
"field_04" integer not null,
|
||||||
"field_06" integer not null,
|
"field_06" integer not null,
|
||||||
"field_08" integer not null,
|
"field_08" integer not null,
|
||||||
"field_0A" integer not null,
|
"field_0a" integer not null,
|
||||||
"field_0C" integer not null,
|
"field_0c" integer not null,
|
||||||
"field_0E" integer not null,
|
"field_0e" integer not null,
|
||||||
"title" integer not null,
|
"title" integer not null,
|
||||||
"background" integer not null
|
"background" integer not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."course_plays" (
|
create table "idz_course_plays" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"course_no" smallint not null,
|
"course_no" integer not null,
|
||||||
"count" integer not null,
|
"count" integer not null,
|
||||||
constraint "course_plays_uq" unique ("profile_id", "course_no")
|
constraint "idz_course_plays_uq" unique ("profile_id", "course_no")
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."car" (
|
create table "idz_car" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"selector" integer not null,
|
"selector" integer not null,
|
||||||
"field_00" integer not null,
|
"field_00" integer not null,
|
||||||
"field_02" integer not null,
|
"field_02" integer not null,
|
||||||
"field_04" integer[] not null,
|
"field_04" text not null,
|
||||||
"field_46" integer not null,
|
"field_46" integer not null,
|
||||||
"field_48" integer not null,
|
"field_48" integer not null,
|
||||||
"field_4A" integer not null,
|
"field_4a" integer not null,
|
||||||
"field_4C" integer not null,
|
"field_4c" integer not null,
|
||||||
"field_50_lo" integer not null,
|
"field_50_lo" integer not null,
|
||||||
"field_50_hi" integer not null,
|
"field_50_hi" integer not null,
|
||||||
"field_58" integer not null,
|
"field_58" integer not null,
|
||||||
"field_5A" integer not null,
|
"field_5a" integer not null,
|
||||||
"field_5B" integer not null,
|
"field_5b" integer not null,
|
||||||
"field_5C" integer not null,
|
"field_5c" integer not null,
|
||||||
"field_5E" integer not null,
|
"field_5e" integer not null,
|
||||||
constraint "car_uq" unique ("profile_id", "selector")
|
constraint "idz_car_uq" unique ("profile_id", "selector")
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."car_selection" (
|
create table "idz_car_selection" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"car_id" bigint not null
|
"car_id" integer not null
|
||||||
references "idz"."car"("id")
|
references "idz_car"("id")
|
||||||
on delete cascade
|
on delete cascade
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."solo_mission_state" (
|
create table "idz_solo_mission_state" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"grid_no" smallint not null,
|
"grid_no" integer not null,
|
||||||
"cell_no" smallint not null,
|
"cell_no" integer not null,
|
||||||
"value" smallint not null,
|
"value" integer not null,
|
||||||
constraint "solo_mission_state_uq" unique ("profile_id", "grid_no", "cell_no")
|
constraint "idz_solo_mission_state_uq" unique (
|
||||||
|
"profile_id",
|
||||||
|
"grid_no",
|
||||||
|
"cell_no"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."settings" (
|
create table "idz_settings" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"music" smallint not null,
|
"music" integer not null,
|
||||||
"pack" bigint not null,
|
"pack" integer not null,
|
||||||
"paper_cup" smallint not null, -- Not a boolean, oddly enough
|
"aura" integer not null,
|
||||||
"gauges" integer not null
|
"paper_cup" integer not null, -- Not a boolean, oddly enough
|
||||||
|
"gauges" integer not null,
|
||||||
|
"driving_style" integer not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."story_state" (
|
create table "idz_stamp_selections" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"x" smallint not null,
|
"stamp_01" integer not null,
|
||||||
"y" smallint not null
|
"stamp_02" integer not null,
|
||||||
|
"stamp_03" integer not null,
|
||||||
|
"stamp_04" integer not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."story_cell_state" (
|
create table "idz_stamp_unlock" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"stamp_no",
|
||||||
|
constraint "idz_stamp_unlock_uq" unique ("profile_id", "stamp_no")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "idz_story_state" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"x" integer not null,
|
||||||
|
"y" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "idz_story_cell_state" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"row_no" integer not null,
|
"row_no" integer not null,
|
||||||
"col_no" integer not null,
|
"col_no" integer not null,
|
||||||
"a" smallint not null,
|
"a" integer not null,
|
||||||
"b" smallint not null,
|
"b" integer not null,
|
||||||
constraint story_cell_state_uq unique ("profile_id", "row_no", "col_no")
|
"c" integer not null,
|
||||||
|
constraint "idz_story_cell_state_uq" unique (
|
||||||
|
"profile_id",
|
||||||
|
"row_no",
|
||||||
|
"col_no"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."free_car" (
|
create table "idz_free_car" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"valid_from" timestamp not null
|
"valid_from" timestamp not null
|
||||||
-- Expiry cannot be controlled by the server
|
-- Expiry cannot be controlled by the server
|
||||||
@@ -132,112 +162,128 @@ create table "idz"."free_car" (
|
|||||||
|
|
||||||
-- Times are stored as floating-point seconds
|
-- Times are stored as floating-point seconds
|
||||||
|
|
||||||
create table "idz"."ta_result" (
|
create table "idz_ta_result" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"route_no" smallint not null,
|
"route_no" integer not null,
|
||||||
"total_time" float not null,
|
"total_time" float not null,
|
||||||
"section_times" float[] not null,
|
"section_times" text not null,
|
||||||
"flags" smallint not null,
|
"flags" integer not null,
|
||||||
"grade" smallint not null,
|
"grade" integer not null,
|
||||||
"car_selector" integer not null,
|
"car_selector" integer not null,
|
||||||
"timestamp" timestamp not null
|
"timestamp" timestamp not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."ta_best" (
|
create table "idz_ta_best" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"route_no" smallint not null,
|
"route_no" integer not null,
|
||||||
"total_time" float not null,
|
"total_time" float not null,
|
||||||
"section_times" float[] not null,
|
"section_times" text not null,
|
||||||
"flags" smallint not null,
|
"flags" integer not null,
|
||||||
"grade" smallint not null, -- TODO enum
|
"grade" integer not null, -- TODO enum
|
||||||
"car_selector" integer not null,
|
"car_selector" integer not null,
|
||||||
"timestamp" timestamp not null,
|
"timestamp" timestamp not null,
|
||||||
constraint "ta_best_uq" unique ("profile_id", "route_no")
|
constraint "idz_ta_best_uq" unique ("profile_id", "route_no")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- TODO ta_section_best
|
-- TODO ta_section_best
|
||||||
|
|
||||||
create table "idz"."background_unlock" (
|
create table "idz_background_unlock" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"background_no" smallint not null,
|
"background_no" integer not null,
|
||||||
constraint "background_unlock_uq" unique ("profile_id", "background_no")
|
constraint "idz_background_unlock_uq" unique (
|
||||||
|
"profile_id",
|
||||||
|
"background_no"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."title_unlock" (
|
create table "idz_title_unlock" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
"profile_id" bigint not null
|
"profile_id" integer not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"title_no" smallint not null,
|
"title_no" integer not null,
|
||||||
constraint "title_unlock_uq" unique ("profile_id", "title_no")
|
constraint "idz_title_unlock_uq" unique ("profile_id", "title_no")
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."unlocks" (
|
create table "idz_unlocks" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"cup" smallint not null,
|
"auras" integer not null,
|
||||||
|
"cup" integer not null,
|
||||||
"gauges" integer not null,
|
"gauges" integer not null,
|
||||||
"music" integer not null,
|
"music" integer not null,
|
||||||
"last_mileage_reward" integer not null
|
"last_mileage_reward" integer not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."team" (
|
create table "idz_team" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null,
|
||||||
|
"version" integer not null,
|
||||||
"ext_id" integer not null,
|
"ext_id" integer not null,
|
||||||
"name" text not null,
|
"name" text not null,
|
||||||
"name_bg" smallint not null,
|
"name_bg" integer not null,
|
||||||
"name_fx" smallint not null,
|
"name_fx" integer not null,
|
||||||
"register_time" timestamp not null,
|
"register_time" timestamp not null,
|
||||||
constraint "team_uq" unique ("ext_id")
|
constraint "idz_team_uq" unique ("version", "ext_id")
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."team" (
|
create table "idz_team_auto" (
|
||||||
"id" bigint primary key not null,
|
"id" integer primary key not null
|
||||||
"ext_id" integer not null,
|
references "idz_team"("id")
|
||||||
"name" text not null,
|
|
||||||
"name_bg" smallint not null,
|
|
||||||
"name_fx" smallint not null,
|
|
||||||
"register_time" timestamp not null,
|
|
||||||
constraint "team_uq" unique ("ext_id")
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "idz"."team_auto" (
|
|
||||||
"id" bigint primary key not null
|
|
||||||
references "idz"."team"("id")
|
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"serial_no" smallint not null,
|
"serial_no" integer not null,
|
||||||
"name_idx" smallint not null,
|
"name_idx" integer not null
|
||||||
constraint "team_auto_uq" unique ("serial_no", "name_idx")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."team_member" (
|
create table "idz_team_member" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "idz"."profile"("id")
|
references "idz_profile"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"team_id" bigint not null
|
"team_id" integer not null
|
||||||
references "idz"."team"("id")
|
references "idz_team"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"join_time" timestamp not null,
|
"join_time" timestamp not null,
|
||||||
"leader" boolean not null
|
"leader" boolean not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table "idz"."team_reservation" (
|
create table "idz_team_reservation" (
|
||||||
"id" bigint primary key not null
|
"id" integer primary key not null
|
||||||
references "aime"."player"("id")
|
references "aime_player"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"team_id" bigint not null
|
"team_id" integer not null
|
||||||
references "idz"."team"("id")
|
references "idz_team"("id")
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
"join_time" timestamp not null,
|
"join_time" timestamp not null,
|
||||||
"leader" boolean not null
|
"leader" boolean not null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create table "idz_weekly_missions" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"weekly_reset" timestamp not null,
|
||||||
|
"mission_left" integer not null,
|
||||||
|
"progress_left" integer not null,
|
||||||
|
"params_left" integer not null,
|
||||||
|
"mission_right" integer not null,
|
||||||
|
"progress_right" integer not null,
|
||||||
|
"params_right" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "idz_my_chara" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"my_chara_no" integer not null,
|
||||||
|
constraint "idz_my_chara_uq" unique ("profile_id", "my_chara_no")
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
create table "meta" ("schemaver" integer not null);
|
create table "meta" ("schemaver" integer not null);
|
||||||
insert into "meta" values (3);
|
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
-- Helper functions which might be useful in one-off queries.
|
|
||||||
-- These are not utilised by any services; those have their own ID generators.
|
|
||||||
|
|
||||||
create or replace function idnum(
|
|
||||||
str text)
|
|
||||||
returns bigint as $$
|
|
||||||
declare
|
|
||||||
num bigint;
|
|
||||||
x integer;
|
|
||||||
begin
|
|
||||||
num := 0;
|
|
||||||
|
|
||||||
for i in 1..11 loop
|
|
||||||
x := ascii(substr(str, i, 1));
|
|
||||||
num := num << 6;
|
|
||||||
|
|
||||||
if x >= 65 and x <= 90 then
|
|
||||||
-- A to Z
|
|
||||||
num = num | (x - 65);
|
|
||||||
elsif x >= 97 and x <= 122 then
|
|
||||||
-- a to z
|
|
||||||
num = num | (x - 71);
|
|
||||||
elsif x >= 48 and x <= 58 then
|
|
||||||
-- 0 to 9
|
|
||||||
num = num | (x + 4);
|
|
||||||
elsif x = 45 then
|
|
||||||
-- Dash
|
|
||||||
num = num | 62;
|
|
||||||
elsif x = 95 then
|
|
||||||
-- Underscore
|
|
||||||
num = num | 63;
|
|
||||||
else
|
|
||||||
raise 'Bad input';
|
|
||||||
end if;
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
return num;
|
|
||||||
end;
|
|
||||||
$$ language plpgsql;
|
|
||||||
|
|
||||||
create or replace function idstr(
|
|
||||||
num bigint)
|
|
||||||
returns text as $$
|
|
||||||
declare
|
|
||||||
a text;
|
|
||||||
pos integer;
|
|
||||||
str text;
|
|
||||||
begin
|
|
||||||
a := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
||||||
str := '';
|
|
||||||
|
|
||||||
for i in 1..11 loop
|
|
||||||
pos := (num & 63);
|
|
||||||
str := substr(a, pos + 1, 1) || str;
|
|
||||||
num := num >> 6;
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
return str;
|
|
||||||
end;
|
|
||||||
$$ language plpgsql;
|
|
||||||
|
|
||||||
create or replace function newid()
|
|
||||||
returns bigint as $$
|
|
||||||
declare
|
|
||||||
bytes bytea;
|
|
||||||
result bigint;
|
|
||||||
begin
|
|
||||||
bytes := gen_random_bytes(8);
|
|
||||||
result := 0;
|
|
||||||
|
|
||||||
for i in 0..7 loop
|
|
||||||
result := (result << 8) | get_byte(bytes, i);
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
-- Truncate high bit to ensure result is positive
|
|
||||||
-- This value is just the decimal representation of 0x7FFFFFFF`FFFFFFFF.
|
|
||||||
|
|
||||||
return result & 9223372036854775807;
|
|
||||||
end;
|
|
||||||
$$ language plpgsql;
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
alter table "idz"."profile" drop column "ext_id";
|
|
||||||
|
|
||||||
update "meta" set "schemaver" = 1;
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
create table "idz"."team" (
|
|
||||||
"id" bigint primary key not null,
|
|
||||||
"ext_id" integer not null,
|
|
||||||
"name" text not null,
|
|
||||||
"name_bg" smallint not null,
|
|
||||||
"name_fx" smallint not null,
|
|
||||||
"register_time" timestamp not null,
|
|
||||||
constraint "team_uq" unique ("ext_id")
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "idz"."team_auto" (
|
|
||||||
"id" bigint primary key not null
|
|
||||||
references "idz"."team"("id")
|
|
||||||
on delete cascade,
|
|
||||||
"serial_no" smallint not null,
|
|
||||||
"name_idx" smallint not null,
|
|
||||||
constraint "team_auto_uq" unique ("serial_no", "name_idx")
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "idz"."team_member" (
|
|
||||||
"id" bigint primary key not null
|
|
||||||
references "idz"."profile"("id")
|
|
||||||
on delete cascade,
|
|
||||||
"team_id" bigint not null
|
|
||||||
references "idz"."team"("id")
|
|
||||||
on delete cascade,
|
|
||||||
"join_time" timestamp not null,
|
|
||||||
"leader" boolean not null
|
|
||||||
);
|
|
||||||
|
|
||||||
create table "idz"."team_reservation" (
|
|
||||||
"id" bigint primary key not null
|
|
||||||
references "aime"."player"("id")
|
|
||||||
on delete cascade,
|
|
||||||
"team_id" bigint not null
|
|
||||||
references "idz"."team"("id")
|
|
||||||
on delete cascade,
|
|
||||||
"join_time" timestamp not null,
|
|
||||||
"leader" boolean not null
|
|
||||||
);
|
|
||||||
|
|
||||||
update "meta" set "schemaver" = 2;
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
-- Can't add NOT NULL or UNIQUE constraints as we'd like to. Fortunately we
|
||||||
|
-- haven't released anything yet so there aren't really any DBs with live
|
||||||
|
-- data out there in the wild.
|
||||||
|
|
||||||
|
-- (Can't drop and recreate the table either btw because "aime_player" is
|
||||||
|
-- transitively referenced by _literally everything_).
|
||||||
|
|
||||||
|
alter table "aime_player" add column "luid" text;
|
||||||
|
alter table "aime_player" add column "access_time" text;
|
||||||
|
|
||||||
|
update "aime_player" as "p"
|
||||||
|
set "luid" = (
|
||||||
|
select "c"."nfc_id"
|
||||||
|
from "aime_card" as "c"
|
||||||
|
where "c"."player_id" = "p"."id"
|
||||||
|
),
|
||||||
|
"access_time" = (
|
||||||
|
select "c"."access_time"
|
||||||
|
from "aime_card" as "c"
|
||||||
|
where "c"."player_id" = "p"."id"
|
||||||
|
);
|
||||||
|
|
||||||
|
drop table "aime_card";
|
||||||
|
|
||||||
|
-- These were never used. Re-create them if they become necessary.
|
||||||
|
drop table "aime_machine";
|
||||||
|
drop table "aime_shop";
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
-- SQLite's ALTER TABLE statement is almost useless, and who knows how much of
|
||||||
|
-- this stuff is present in older versions. So while ideally we'd mark a lot
|
||||||
|
-- of these columns NOT NULL that might come back to bite us as we extend
|
||||||
|
-- support downward from Chunithm 4 to Chunithm 1.
|
||||||
|
|
||||||
|
create table "cm_user_data" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
-- Could in theory do a shared primary key with aime_player, since this
|
||||||
|
-- is going to be a 1:1 relation for the foreseeable future, but again
|
||||||
|
-- the SQLite strait-jacket forces us to design defensively.
|
||||||
|
"player_id" integer not null
|
||||||
|
references "aime_player"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"access_code" text,
|
||||||
|
"user_name" text,
|
||||||
|
"is_web_join" text,
|
||||||
|
"web_limit_date" text,
|
||||||
|
"level" integer,
|
||||||
|
"reincarnation_num" integer,
|
||||||
|
"exp" integer,
|
||||||
|
"point" integer,
|
||||||
|
"total_point" integer,
|
||||||
|
"play_count" integer,
|
||||||
|
"multi_play_count" integer,
|
||||||
|
"multi_win_count" integer,
|
||||||
|
"request_res_count" integer,
|
||||||
|
"accept_res_count" integer,
|
||||||
|
"success_res_count" integer,
|
||||||
|
"player_rating" integer,
|
||||||
|
"highest_rating" integer,
|
||||||
|
"nameplate_id" integer,
|
||||||
|
"frame_id" integer,
|
||||||
|
"character_id" integer,
|
||||||
|
"trophy_id" integer,
|
||||||
|
"played_tutorial_bit" integer,
|
||||||
|
"first_tutorial_cancel_num" integer,
|
||||||
|
"master_tutorial_cancel_num" integer,
|
||||||
|
"total_repertoire_count" integer,
|
||||||
|
"total_map_num" integer,
|
||||||
|
"total_hi_score" integer,
|
||||||
|
"total_basic_high_score" integer,
|
||||||
|
"total_advanced_high_score" integer,
|
||||||
|
"total_expert_high_score" integer,
|
||||||
|
"total_master_high_score" integer,
|
||||||
|
"event_watched_date" text,
|
||||||
|
"friend_count" integer,
|
||||||
|
"is_maimai" text,
|
||||||
|
"first_game_id" text,
|
||||||
|
"first_rom_version" text,
|
||||||
|
"first_data_version" text,
|
||||||
|
"first_play_date" text,
|
||||||
|
"last_game_id" text,
|
||||||
|
"last_rom_version" text,
|
||||||
|
"last_data_version" text,
|
||||||
|
"last_play_date" text,
|
||||||
|
"last_place_id" integer,
|
||||||
|
"last_place_name" text,
|
||||||
|
"last_region_id" text,
|
||||||
|
"last_region_name" text,
|
||||||
|
"last_all_net_id" text,
|
||||||
|
"last_client_id" text
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_activity" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"kind" integer not null,
|
||||||
|
-- This is just called "id" on the wire but, well, we already have an "id"
|
||||||
|
-- column up there ^
|
||||||
|
"activity_id" integer not null,
|
||||||
|
"sort_number" integer not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
constraint "cm_user_activity_uq" unique (
|
||||||
|
"profile_id",
|
||||||
|
"kind",
|
||||||
|
"activity_id"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_data_ex" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"compatible_cm_version" text not null,
|
||||||
|
"medal" integer not null,
|
||||||
|
"map_icon_id" integer not null,
|
||||||
|
"voice_id" integer not null,
|
||||||
|
"ext1" integer not null,
|
||||||
|
"ext2" integer not null,
|
||||||
|
"ext3" integer not null,
|
||||||
|
"ext4" integer not null,
|
||||||
|
"ext5" integer not null,
|
||||||
|
"ext6" integer not null,
|
||||||
|
"ext7" integer not null,
|
||||||
|
"ext8" integer not null,
|
||||||
|
"ext9" integer not null,
|
||||||
|
"ext10" integer not null,
|
||||||
|
"ext11" integer not null,
|
||||||
|
"ext12" integer not null,
|
||||||
|
"ext13" integer not null,
|
||||||
|
"ext14" integer not null,
|
||||||
|
"ext15" integer not null,
|
||||||
|
"ext16" integer not null,
|
||||||
|
"ext17" integer not null,
|
||||||
|
"ext18" integer not null,
|
||||||
|
"ext19" integer not null,
|
||||||
|
"ext20" integer not null,
|
||||||
|
"ext_str1" text not null,
|
||||||
|
"ext_str2" text not null,
|
||||||
|
"ext_str3" text not null,
|
||||||
|
"ext_str4" text not null,
|
||||||
|
"ext_str5" text not null,
|
||||||
|
"ext_long1" integer not null,
|
||||||
|
"ext_long2" integer not null,
|
||||||
|
"ext_long3" integer not null,
|
||||||
|
"ext_long4" integer not null,
|
||||||
|
"ext_long5" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_character" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"character_id" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"level" integer not null,
|
||||||
|
"skill_id" integer not null,
|
||||||
|
"friendship_exp" integer not null,
|
||||||
|
"is_valid" integer not null,
|
||||||
|
"is_new_mark" integer not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
constraint "cm_user_character_uq" unique ("profile_id", "character_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_game_option" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"bg_info" integer not null,
|
||||||
|
"field_color" integer not null,
|
||||||
|
"guide_sound" integer not null,
|
||||||
|
"sound_effect" integer not null,
|
||||||
|
"guide_line" integer not null,
|
||||||
|
"speed" integer not null,
|
||||||
|
"option_set" integer not null,
|
||||||
|
"matching" integer not null,
|
||||||
|
"judge_pos" integer not null,
|
||||||
|
"rating" integer not null,
|
||||||
|
"judge_justice" integer not null,
|
||||||
|
"judge_attack" integer not null,
|
||||||
|
"headphone" integer not null,
|
||||||
|
"player_level" integer not null,
|
||||||
|
"success_tap" integer not null,
|
||||||
|
"success_ex_tap" integer not null,
|
||||||
|
"success_slide_hold" integer not null,
|
||||||
|
"success_air" integer not null,
|
||||||
|
"success_flick" integer not null,
|
||||||
|
"success_skill" integer not null,
|
||||||
|
"success_tap_timbre" integer not null,
|
||||||
|
"privacy" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_game_option_ex" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"ext1" integer not null,
|
||||||
|
"ext2" integer not null,
|
||||||
|
"ext3" integer not null,
|
||||||
|
"ext4" integer not null,
|
||||||
|
"ext5" integer not null,
|
||||||
|
"ext6" integer not null,
|
||||||
|
"ext7" integer not null,
|
||||||
|
"ext8" integer not null,
|
||||||
|
"ext9" integer not null,
|
||||||
|
"ext10" integer not null,
|
||||||
|
"ext11" integer not null,
|
||||||
|
"ext12" integer not null,
|
||||||
|
"ext13" integer not null,
|
||||||
|
"ext14" integer not null,
|
||||||
|
"ext15" integer not null,
|
||||||
|
"ext16" integer not null,
|
||||||
|
"ext17" integer not null,
|
||||||
|
"ext18" integer not null,
|
||||||
|
"ext19" integer not null,
|
||||||
|
"ext20" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_item" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"item_kind" integer not null,
|
||||||
|
"item_id" integer not null,
|
||||||
|
"stock" integer not null,
|
||||||
|
"is_valid" text not null,
|
||||||
|
constraint "cm_user_item_uq" unique ("profile_id", "item_kind", "item_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_map" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"map_id" integer not null,
|
||||||
|
"position" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
"area_id" integer not null,
|
||||||
|
"route_number" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"rate" integer not null,
|
||||||
|
"status_count" integer not null,
|
||||||
|
"is_valid" text not null,
|
||||||
|
constraint "cm_user_map_uq" unique ("profile_id", "map_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_music" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"music_id" integer not null,
|
||||||
|
"level" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"score_max" integer not null,
|
||||||
|
"res_request_count" integer not null,
|
||||||
|
"res_accept_count" integer not null,
|
||||||
|
"res_success_count" integer not null,
|
||||||
|
"miss_count" integer not null,
|
||||||
|
"max_combo_count" integer not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_success" text not null,
|
||||||
|
"full_chain" integer not null,
|
||||||
|
"max_chain" integer not null,
|
||||||
|
"score_rank" integer not null,
|
||||||
|
"is_lock" text not null,
|
||||||
|
constraint "cm_user_music_uq" unique ("profile_id", "music_id", "level")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "cm_user_playlog" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"order_id" integer not null,
|
||||||
|
"sort_number" integer not null,
|
||||||
|
"place_id" integer not null,
|
||||||
|
"play_date" text not null,
|
||||||
|
"user_play_date" text not null,
|
||||||
|
"music_id" integer not null,
|
||||||
|
"level" integer not null,
|
||||||
|
"custom_id" integer not null,
|
||||||
|
"played_user_id1" integer not null,
|
||||||
|
"played_user_id2" integer not null,
|
||||||
|
"played_user_id3" integer not null,
|
||||||
|
"played_user_name1" text not null,
|
||||||
|
"played_user_name2" text not null,
|
||||||
|
"played_user_name3" text not null,
|
||||||
|
"played_music_level1" integer not null,
|
||||||
|
"played_music_level2" integer not null,
|
||||||
|
"played_music_level3" integer not null,
|
||||||
|
"played_custom1" integer not null,
|
||||||
|
"played_custom2" integer not null,
|
||||||
|
"played_custom3" integer not null,
|
||||||
|
"track" integer not null,
|
||||||
|
"score" integer not null,
|
||||||
|
"rank" integer not null,
|
||||||
|
"max_combo" integer not null,
|
||||||
|
"max_chain" integer not null,
|
||||||
|
"rate_tap" integer not null,
|
||||||
|
"rate_hold" integer not null,
|
||||||
|
"rate_slide" integer not null,
|
||||||
|
"rate_air" integer not null,
|
||||||
|
"rate_flick" integer not null,
|
||||||
|
"judge_guilty" integer not null,
|
||||||
|
"judge_attack" integer not null,
|
||||||
|
"judge_justice" integer not null,
|
||||||
|
"judge_critical" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"player_rating" integer not null,
|
||||||
|
"is_new_record" text not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"full_chain_kind" integer not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_continue" text not null,
|
||||||
|
"is_free_to_play" text not null,
|
||||||
|
"character_id" integer not null,
|
||||||
|
"skill_id" integer not null,
|
||||||
|
"play_kind" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
"skill_level" integer not null,
|
||||||
|
"skill_effect" integer not null,
|
||||||
|
"place_name" text not null,
|
||||||
|
"is_maimai" text not null
|
||||||
|
);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- This adds the required columns to save player aura settings and unlocks
|
||||||
|
-- Default values are set according to what the game expects
|
||||||
|
|
||||||
|
alter table "idz_settings" add column "aura" integer NOT NULL DEFAULT '0';
|
||||||
|
alter table "idz_unlocks" add column "auras" integer NOT NULL DEFAULT '1';
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
create table "cm_user_duel_list" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"duel_id" integer not null,
|
||||||
|
"progress" integer not null,
|
||||||
|
"point" integer not null,
|
||||||
|
"is_clear" boolean not null,
|
||||||
|
"last_play_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
constraint "cm_user_duel_list_uq" unique ("profile_id", "duel_id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
create table "cm_user_course" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"course_id" integer not null,
|
||||||
|
"class_id" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"score_max" integer not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_success" text not null,
|
||||||
|
"score_rank" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"last_play_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
constraint "cm_user_course_uq" unique ("profile_id", "course_id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- This was not present in new DBs initialized to schema version 11.
|
||||||
|
create table if not exists "cm_user_course" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"course_id" integer not null,
|
||||||
|
"class_id" integer not null,
|
||||||
|
"play_count" integer not null,
|
||||||
|
"score_max" integer not null,
|
||||||
|
"is_full_combo" text not null,
|
||||||
|
"is_all_justice" text not null,
|
||||||
|
"is_success" text not null,
|
||||||
|
"score_rank" integer not null,
|
||||||
|
"event_id" integer not null,
|
||||||
|
"last_play_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
"is_clear" text not null,
|
||||||
|
constraint "cm_user_course_uq" unique ("profile_id", "course_id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- This was also not present in the db init scripts...
|
||||||
|
create table if not exists "cm_user_duel_list" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"duel_id" integer not null,
|
||||||
|
"progress" integer not null,
|
||||||
|
"point" integer not null,
|
||||||
|
"is_clear" boolean not null,
|
||||||
|
"last_play_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param3" integer not null,
|
||||||
|
"param4" integer not null,
|
||||||
|
constraint "cm_user_duel_list_uq" unique ("profile_id", "duel_id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
create table if not exists "cm_user_charge" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"charge_id" integer not null,
|
||||||
|
"stock" integer not null,
|
||||||
|
"purchase_date" text not null,
|
||||||
|
"valid_date" text not null,
|
||||||
|
"param1" integer not null,
|
||||||
|
"param2" integer not null,
|
||||||
|
"param_date" text not null,
|
||||||
|
constraint "cm_user_charge_uq" unique ("profile_id", "charge_id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
create table if not exists "cm_user_recent_rating" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "cm_user_data"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"sort_order" integer not null,
|
||||||
|
"music_id" integer not null,
|
||||||
|
"difficult_id" integer not null,
|
||||||
|
"rom_version_code" integer not null,
|
||||||
|
"score" integer not null,
|
||||||
|
constraint "cm_user_recent_rating_uq" unique ("profile_id", "sort_order")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Prepopulate this table by backfilling the most recent 30 scores per user.
|
||||||
|
-- This isn't exactly correct since not every recent score should go in here, but it's probably close enough.
|
||||||
|
INSERT INTO cm_user_recent_rating (profile_id, sort_order, music_id, difficult_id, rom_version_code, score)
|
||||||
|
SELECT * FROM (
|
||||||
|
SELECT
|
||||||
|
profile_id,
|
||||||
|
row_number()
|
||||||
|
OVER (PARTITION BY profile_id ORDER BY user_play_date DESC) AS sort_order,
|
||||||
|
music_id,
|
||||||
|
level AS difficult_id,
|
||||||
|
'1030000' AS rom_version_code,
|
||||||
|
score
|
||||||
|
FROM cm_user_playlog
|
||||||
|
WHERE
|
||||||
|
difficult_id < 4 -- skip world's end
|
||||||
|
ORDER BY profile_id ASC, user_play_date DESC
|
||||||
|
)
|
||||||
|
WHERE sort_order <= 30;
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
create table "new_idz_profile" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"player_id" integer not null
|
||||||
|
references "aime_player"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"version" integer not null,
|
||||||
|
"name" text not null,
|
||||||
|
"lv" integer not null,
|
||||||
|
"exp" integer not null,
|
||||||
|
"fame" integer not null,
|
||||||
|
"dpoint" integer not null,
|
||||||
|
"mileage" integer not null,
|
||||||
|
"register_time" timestamp not null,
|
||||||
|
"access_time" timestamp not null,
|
||||||
|
constraint "idz_profile_player_uq" unique ("player_id", "version")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "new_idz_team" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"version" integer not null,
|
||||||
|
"ext_id" integer not null,
|
||||||
|
"name" text not null,
|
||||||
|
"name_bg" integer not null,
|
||||||
|
"name_fx" integer not null,
|
||||||
|
"register_time" timestamp not null,
|
||||||
|
constraint "idz_team_uq" unique ("version", "ext_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into "new_idz_profile" (
|
||||||
|
"id",
|
||||||
|
"player_id",
|
||||||
|
"version",
|
||||||
|
"name",
|
||||||
|
"lv",
|
||||||
|
"exp",
|
||||||
|
"fame",
|
||||||
|
"dpoint",
|
||||||
|
"mileage",
|
||||||
|
"register_time",
|
||||||
|
"access_time"
|
||||||
|
) select
|
||||||
|
x."id",
|
||||||
|
x."player_id",
|
||||||
|
1,
|
||||||
|
x."name",
|
||||||
|
x."lv",
|
||||||
|
x."exp",
|
||||||
|
x."fame",
|
||||||
|
x."dpoint",
|
||||||
|
x."mileage",
|
||||||
|
x."register_time",
|
||||||
|
x."access_time"
|
||||||
|
from "idz_profile" as "x";
|
||||||
|
|
||||||
|
insert into "new_idz_team" (
|
||||||
|
"id",
|
||||||
|
"version",
|
||||||
|
"ext_id",
|
||||||
|
"name",
|
||||||
|
"name_bg",
|
||||||
|
"name_fx",
|
||||||
|
"register_time"
|
||||||
|
) select
|
||||||
|
x."id",
|
||||||
|
1,
|
||||||
|
x."ext_id",
|
||||||
|
x."name",
|
||||||
|
x."name_bg",
|
||||||
|
x."name_fx",
|
||||||
|
x."register_time"
|
||||||
|
from "idz_team" as "x";
|
||||||
|
|
||||||
|
drop table "idz_profile";
|
||||||
|
drop table "idz_team";
|
||||||
|
|
||||||
|
alter table "new_idz_profile" rename to "idz_profile";
|
||||||
|
alter table "new_idz_team" rename to "idz_team";
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
create table "idz_my_chara" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"my_chara_no" integer not null,
|
||||||
|
constraint "idz_my_chara_uq" unique ("profile_id", "my_chara_no")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "new_idz_settings" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"music" integer not null,
|
||||||
|
"pack" integer not null,
|
||||||
|
"aura" integer not null,
|
||||||
|
"paper_cup" integer not null, -- Not a boolean, oddly enough
|
||||||
|
"gauges" integer not null,
|
||||||
|
"driving_style" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "idz_stamp_selections" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"stamp_01" integer not null,
|
||||||
|
"stamp_02" integer not null,
|
||||||
|
"stamp_03" integer not null,
|
||||||
|
"stamp_04" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "idz_stamp_unlock" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"stamp_no",
|
||||||
|
constraint "idz_stamp_unlock_uq" unique ("profile_id", "stamp_no")
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "new_idz_story_cell_state" (
|
||||||
|
"id" integer primary key not null,
|
||||||
|
"profile_id" integer not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"row_no" integer not null,
|
||||||
|
"col_no" integer not null,
|
||||||
|
"a" integer not null,
|
||||||
|
"b" integer not null,
|
||||||
|
"c" integer not null,
|
||||||
|
constraint "idz_story_cell_state_uq" unique (
|
||||||
|
"profile_id",
|
||||||
|
"row_no",
|
||||||
|
"col_no"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
create table "idz_weekly_missions" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "idz_profile"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"weekly_reset" timestamp not null,
|
||||||
|
"mission_left" integer not null,
|
||||||
|
"progress_left" integer not null,
|
||||||
|
"params_left" integer not null,
|
||||||
|
"mission_right" integer not null,
|
||||||
|
"progress_right" integer not null,
|
||||||
|
"params_right" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into "new_idz_settings" (
|
||||||
|
"id",
|
||||||
|
"music",
|
||||||
|
"pack",
|
||||||
|
"aura",
|
||||||
|
"paper_cup",
|
||||||
|
"gauges",
|
||||||
|
"driving_style"
|
||||||
|
) select
|
||||||
|
x."id",
|
||||||
|
x."music",
|
||||||
|
x."pack",
|
||||||
|
x."aura",
|
||||||
|
x."paper_cup",
|
||||||
|
x."gauges",
|
||||||
|
0
|
||||||
|
from "idz_settings" as x;
|
||||||
|
|
||||||
|
insert into "new_idz_story_cell_state" (
|
||||||
|
"id",
|
||||||
|
"profile_id",
|
||||||
|
"row_no",
|
||||||
|
"col_no",
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c"
|
||||||
|
) select
|
||||||
|
x."id",
|
||||||
|
x."profile_id",
|
||||||
|
x."row_no",
|
||||||
|
x."col_no",
|
||||||
|
x."a",
|
||||||
|
x."b",
|
||||||
|
0
|
||||||
|
from "idz_story_cell_state" as x;
|
||||||
|
|
||||||
|
drop table "idz_settings";
|
||||||
|
drop table "idz_story_cell_state";
|
||||||
|
|
||||||
|
alter table "new_idz_settings" rename to "idz_settings";
|
||||||
|
alter table "new_idz_story_cell_state" rename to "idz_story_cell_state";
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
create table "new_idz_team_auto" (
|
||||||
|
"id" integer primary key not null
|
||||||
|
references "idz_team"("id")
|
||||||
|
on delete cascade,
|
||||||
|
"serial_no" integer not null,
|
||||||
|
"name_idx" integer not null
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into "new_idz_team_auto"
|
||||||
|
select "id", "serial_no", "name_idx" from "idz_team_auto";
|
||||||
|
|
||||||
|
drop table "idz_team_auto";
|
||||||
|
alter table "new_idz_team_auto" rename to "idz_team_auto";
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import { PoolClient } from "pg";
|
|
||||||
import * as sql from "sql-bricks";
|
|
||||||
|
|
||||||
import { CardRepository, Transaction } from "./repo";
|
|
||||||
import { connect, generateId, generateExtId } from "../db";
|
|
||||||
import { AimeId } from "../model";
|
|
||||||
|
|
||||||
class CardRepositoryImpl implements CardRepository {
|
|
||||||
constructor(private readonly _conn: PoolClient) {}
|
|
||||||
|
|
||||||
async lookup(luid: string, now: Date): Promise<AimeId | undefined> {
|
|
||||||
const fetchSql = sql
|
|
||||||
.select("c.id", "p.ext_id")
|
|
||||||
.from("aime.card c")
|
|
||||||
.join("aime.player p", { "c.player_id": "p.id" })
|
|
||||||
.where("c.nfc_id", luid)
|
|
||||||
.toParams();
|
|
||||||
|
|
||||||
const { rows } = await this._conn.query(fetchSql);
|
|
||||||
|
|
||||||
if (rows.length === 0) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = rows[0].id;
|
|
||||||
const extId = rows[0].ext_id;
|
|
||||||
|
|
||||||
const touchSql = sql
|
|
||||||
.update("aime.card")
|
|
||||||
.set({ access_time: now })
|
|
||||||
.where("id", id)
|
|
||||||
.toParams();
|
|
||||||
|
|
||||||
await this._conn.query(touchSql);
|
|
||||||
|
|
||||||
return extId;
|
|
||||||
}
|
|
||||||
|
|
||||||
async register(luid: string, now: Date): Promise<AimeId> {
|
|
||||||
const playerId = generateId();
|
|
||||||
const cardId = generateId();
|
|
||||||
const aimeId = generateExtId() as AimeId;
|
|
||||||
|
|
||||||
const playerSql = sql
|
|
||||||
.insert("aime.player", {
|
|
||||||
id: playerId,
|
|
||||||
ext_id: aimeId,
|
|
||||||
register_time: now,
|
|
||||||
})
|
|
||||||
.toParams();
|
|
||||||
|
|
||||||
await this._conn.query(playerSql);
|
|
||||||
|
|
||||||
const cardSql = sql
|
|
||||||
.insert("aime.card", {
|
|
||||||
id: cardId,
|
|
||||||
player_id: playerId,
|
|
||||||
nfc_id: luid,
|
|
||||||
register_time: now,
|
|
||||||
access_time: now,
|
|
||||||
})
|
|
||||||
.toParams();
|
|
||||||
|
|
||||||
await this._conn.query(cardSql);
|
|
||||||
|
|
||||||
return aimeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TransactionImpl implements Transaction {
|
|
||||||
constructor(private readonly _conn: PoolClient) {}
|
|
||||||
|
|
||||||
cards(): CardRepository {
|
|
||||||
return new CardRepositoryImpl(this._conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
async commit(): Promise<void> {
|
|
||||||
await this._conn.query("commit");
|
|
||||||
await this._conn.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
async rollback(): Promise<void> {
|
|
||||||
await this._conn.query("rollback");
|
|
||||||
await this._conn.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function beginDbSession(): Promise<Transaction> {
|
|
||||||
const conn = await connect();
|
|
||||||
|
|
||||||
await conn.query("begin");
|
|
||||||
|
|
||||||
return new TransactionImpl(conn);
|
|
||||||
}
|
|
||||||
@@ -105,7 +105,7 @@ test("decode lookup", () => {
|
|||||||
|
|
||||||
const obj = decode(req);
|
const obj = decode(req);
|
||||||
|
|
||||||
expect(obj.type).toBe("lookup");
|
expect(obj.type).toBe("lookup2");
|
||||||
expect(obj.gameId).toBe("SDBT");
|
expect(obj.gameId).toBe("SDBT");
|
||||||
expect(obj.keychipId).toBe("A69E01A9999");
|
expect(obj.keychipId).toBe("A69E01A9999");
|
||||||
expect(obj.luid).toBe("01036495850523030676");
|
expect(obj.luid).toBe("01036495850523030676");
|
||||||
|
|||||||
+18
-1
@@ -1,7 +1,10 @@
|
|||||||
|
import logger from "debug";
|
||||||
import { Transform } from "stream";
|
import { Transform } from "stream";
|
||||||
|
|
||||||
import * as Request from "./request";
|
import * as Request from "./request";
|
||||||
|
|
||||||
|
const debug = logger("app:aimedb:decoder");
|
||||||
|
|
||||||
function begin(msg: Buffer): Request.AimeRequestBase {
|
function begin(msg: Buffer): Request.AimeRequestBase {
|
||||||
const gameId = msg.toString("ascii", 0x000a, 0x000e);
|
const gameId = msg.toString("ascii", 0x000a, 0x000e);
|
||||||
const keychipId = msg.toString("ascii", 0x0014, 0x001f);
|
const keychipId = msg.toString("ascii", 0x0014, 0x001f);
|
||||||
@@ -28,6 +31,15 @@ function readFeliCaLookupRequest(msg: Buffer): Request.FeliCaLookupRequest {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readFeliCaLookupRequest2(msg: Buffer): Request.FeliCaLookup2Request {
|
||||||
|
return {
|
||||||
|
...begin(msg),
|
||||||
|
type: "felica_lookup2",
|
||||||
|
idm: msg.slice(0x0030, 0x0038).toString("hex"),
|
||||||
|
pmm: msg.slice(0x0038, 0x0040).toString("hex"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function readLogRequest(msg: Buffer): Request.LogRequest {
|
function readLogRequest(msg: Buffer): Request.LogRequest {
|
||||||
// idk what any of this stuff means yet
|
// idk what any of this stuff means yet
|
||||||
// field20 and field28 appear to be an aime id but that is all.
|
// field20 and field28 appear to be an aime id but that is all.
|
||||||
@@ -95,6 +107,7 @@ readers.set(0x0009, readLogRequest);
|
|||||||
readers.set(0x000b, readCampaignRequest);
|
readers.set(0x000b, readCampaignRequest);
|
||||||
readers.set(0x000d, readRegisterRequest);
|
readers.set(0x000d, readRegisterRequest);
|
||||||
readers.set(0x000f, readLookupRequest2);
|
readers.set(0x000f, readLookupRequest2);
|
||||||
|
readers.set(0x0011, readFeliCaLookupRequest2);
|
||||||
readers.set(0x0064, readHelloRequest);
|
readers.set(0x0064, readHelloRequest);
|
||||||
readers.set(0x0066, readGoodbyeRequest);
|
readers.set(0x0066, readGoodbyeRequest);
|
||||||
|
|
||||||
@@ -116,6 +129,10 @@ export class Decoder extends Transform {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callback(null, reader(msg));
|
const obj = reader(msg);
|
||||||
|
|
||||||
|
debug("Decode %j", obj);
|
||||||
|
|
||||||
|
return callback(null, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-3
@@ -1,7 +1,10 @@
|
|||||||
|
import logger from "debug";
|
||||||
import { Transform } from "stream";
|
import { Transform } from "stream";
|
||||||
|
|
||||||
import { AimeResponse, RegisterLevel } from "./response";
|
import { AimeResponse, RegisterLevel } from "./response";
|
||||||
|
|
||||||
|
const debug = logger("app:aimedb:encoder");
|
||||||
|
|
||||||
const registerLevels = new Map<RegisterLevel, number>();
|
const registerLevels = new Map<RegisterLevel, number>();
|
||||||
|
|
||||||
registerLevels.set("none", 0);
|
registerLevels.set("none", 0);
|
||||||
@@ -11,7 +14,7 @@ registerLevels.set("segaid", 2);
|
|||||||
function begin(length: number) {
|
function begin(length: number) {
|
||||||
const buf = Buffer.alloc(length);
|
const buf = Buffer.alloc(length);
|
||||||
|
|
||||||
buf.writeUInt16LE(0xa13e, 0x0000); // Magic?
|
buf.writeUInt16LE(0xa13e, 0x0000); // Magic: aime
|
||||||
buf.writeUInt16LE(0x3087, 0x0002); // ???
|
buf.writeUInt16LE(0x3087, 0x0002); // ???
|
||||||
buf.writeUInt16LE(length, 0x0006);
|
buf.writeUInt16LE(length, 0x0006);
|
||||||
|
|
||||||
@@ -27,7 +30,7 @@ export class Encoder extends Transform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_transform(msg: AimeResponse, encoding, callback) {
|
_transform(msg: AimeResponse, encoding, callback) {
|
||||||
console.log("Aimedb: Encode", msg);
|
debug("Encode %j", msg);
|
||||||
|
|
||||||
let buf: Buffer;
|
let buf: Buffer;
|
||||||
|
|
||||||
@@ -40,6 +43,18 @@ export class Encoder extends Transform {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "felica_lookup2":
|
||||||
|
buf = begin(0x0140);
|
||||||
|
buf.writeUInt16LE(0x0012, 0x0004); // cmd code
|
||||||
|
buf.writeUInt16LE(msg.status, 0x0008);
|
||||||
|
buf.writeInt32LE(msg.aimeId || -1, 0x0020);
|
||||||
|
buf.writeUInt32LE(0xffffffff, 0x0024); // FF
|
||||||
|
buf.writeUInt32LE(0xffffffff, 0x0028); // FF
|
||||||
|
buf.write(msg.accessCode, 0x002c, "hex");
|
||||||
|
buf.writeUInt16LE(0x0001, 0x0037); // 00 01
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case "hello":
|
case "hello":
|
||||||
buf = begin(0x0020);
|
buf = begin(0x0020);
|
||||||
buf.writeUInt16LE(0x0065, 0x0004); // cmd code
|
buf.writeUInt16LE(0x0065, 0x0004); // cmd code
|
||||||
@@ -105,7 +120,9 @@ export class Encoder extends Transform {
|
|||||||
return callback(new Error("Unimplemented response type"));
|
return callback(new Error("Unimplemented response type"));
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Aimedb: Send", buf.toString("hex"));
|
if (debug.enabled) {
|
||||||
|
debug("Send %s", buf.toString("hex"));
|
||||||
|
}
|
||||||
|
|
||||||
return callback(null, buf);
|
return callback(null, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -1,5 +1,8 @@
|
|||||||
|
import logger from "debug";
|
||||||
import { Transform } from "stream";
|
import { Transform } from "stream";
|
||||||
|
|
||||||
|
const debug = logger("app:aimedb:frame");
|
||||||
|
|
||||||
export class Deframer extends Transform {
|
export class Deframer extends Transform {
|
||||||
private state: Buffer;
|
private state: Buffer;
|
||||||
|
|
||||||
@@ -33,7 +36,9 @@ export class Deframer extends Transform {
|
|||||||
|
|
||||||
const frame = this.state.slice(0, len);
|
const frame = this.state.slice(0, len);
|
||||||
|
|
||||||
console.log("Aimedb: Recv", frame.toString("hex"));
|
if (debug.enabled) {
|
||||||
|
debug("Recv %s", frame.toString("hex"));
|
||||||
|
}
|
||||||
|
|
||||||
this.state = this.state.slice(len);
|
this.state = this.state.slice(len);
|
||||||
|
|
||||||
|
|||||||
+37
-8
@@ -1,13 +1,17 @@
|
|||||||
|
import logger from "debug";
|
||||||
|
|
||||||
import { Repositories } from "./repo";
|
import { Repositories } from "./repo";
|
||||||
import * as Req from "./request";
|
import * as Req from "./request";
|
||||||
import * as Res from "./response";
|
import * as Res from "./response";
|
||||||
|
|
||||||
|
const debug = logger("app:aimedb:ops");
|
||||||
|
|
||||||
function hello(
|
function hello(
|
||||||
rep: Repositories,
|
rep: Repositories,
|
||||||
req: Req.HelloRequest,
|
req: Req.HelloRequest,
|
||||||
now: Date
|
now: Date
|
||||||
): Res.HelloResponse {
|
): Res.HelloResponse {
|
||||||
console.log("Aimedb: Hello");
|
debug("Hello");
|
||||||
|
|
||||||
return { type: req.type, status: 1 };
|
return { type: req.type, status: 1 };
|
||||||
}
|
}
|
||||||
@@ -17,7 +21,7 @@ function campaign(
|
|||||||
req: Req.CampaignRequest,
|
req: Req.CampaignRequest,
|
||||||
now: Date
|
now: Date
|
||||||
): Res.CampaignResponse {
|
): Res.CampaignResponse {
|
||||||
console.log("Aimedb: Campaign stuff");
|
debug("Campaign stuff");
|
||||||
|
|
||||||
return { type: req.type, status: 1 };
|
return { type: req.type, status: 1 };
|
||||||
}
|
}
|
||||||
@@ -27,7 +31,7 @@ function feliCaLookup(
|
|||||||
req: Req.FeliCaLookupRequest,
|
req: Req.FeliCaLookupRequest,
|
||||||
now: Date
|
now: Date
|
||||||
): Res.FeliCaLookupResponse {
|
): Res.FeliCaLookupResponse {
|
||||||
console.log("Aimedb: FeliCa access code lookup");
|
debug("FeliCa access code lookup");
|
||||||
|
|
||||||
// Well, this access code transformation is the million dollar question eh
|
// Well, this access code transformation is the million dollar question eh
|
||||||
// Return a decimal representation for now.
|
// Return a decimal representation for now.
|
||||||
@@ -42,12 +46,34 @@ function feliCaLookup(
|
|||||||
return { type: req.type, status: 1, accessCode };
|
return { type: req.type, status: 1, accessCode };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function feliCaLookup2(
|
||||||
|
rep: Repositories,
|
||||||
|
req: Req.FeliCaLookup2Request,
|
||||||
|
now: Date
|
||||||
|
): Promise<Res.FeliCaLookup2Response> {
|
||||||
|
debug("FeliCa access code lookup");
|
||||||
|
|
||||||
|
const num = BigInt("0x" + req.idm);
|
||||||
|
let accessCode = num.toString();
|
||||||
|
|
||||||
|
while (accessCode.length < 20) {
|
||||||
|
accessCode = "0" + accessCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: req.type,
|
||||||
|
status: 1,
|
||||||
|
accessCode,
|
||||||
|
aimeId: await rep.cards().lookup(accessCode, now),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function lookup(
|
async function lookup(
|
||||||
rep: Repositories,
|
rep: Repositories,
|
||||||
req: Req.LookupRequest,
|
req: Req.LookupRequest,
|
||||||
now: Date
|
now: Date
|
||||||
): Promise<Res.LookupResponse> {
|
): Promise<Res.LookupResponse> {
|
||||||
console.log("Aimedb: Mifare lookup v1", req.luid);
|
debug("Mifare lookup: luid=%s", req.luid);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: req.type,
|
type: req.type,
|
||||||
@@ -62,7 +88,7 @@ async function lookup2(
|
|||||||
req: Req.LookupRequest2,
|
req: Req.LookupRequest2,
|
||||||
now: Date
|
now: Date
|
||||||
): Promise<Res.LookupResponse2> {
|
): Promise<Res.LookupResponse2> {
|
||||||
console.log("Aimedb: Mifare lookup v2", req.luid);
|
debug("FeliCa lookup: luid=%s", req.luid);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: req.type,
|
type: req.type,
|
||||||
@@ -77,7 +103,7 @@ async function register(
|
|||||||
req: Req.RegisterRequest,
|
req: Req.RegisterRequest,
|
||||||
now: Date
|
now: Date
|
||||||
): Promise<Res.RegisterResponse> {
|
): Promise<Res.RegisterResponse> {
|
||||||
console.log("Aimedb: Mifare register", req.luid);
|
debug("User register: luid=%s", req.luid);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: req.type,
|
type: req.type,
|
||||||
@@ -91,7 +117,7 @@ function log(
|
|||||||
req: Req.LogRequest,
|
req: Req.LogRequest,
|
||||||
now: Date
|
now: Date
|
||||||
): Res.LogResponse {
|
): Res.LogResponse {
|
||||||
console.log("Aimedb: Log message");
|
debug("Log message");
|
||||||
|
|
||||||
return { type: req.type, status: 1 };
|
return { type: req.type, status: 1 };
|
||||||
}
|
}
|
||||||
@@ -111,6 +137,9 @@ export async function dispatch(
|
|||||||
case "felica_lookup":
|
case "felica_lookup":
|
||||||
return feliCaLookup(rep, req, now);
|
return feliCaLookup(rep, req, now);
|
||||||
|
|
||||||
|
case "felica_lookup2":
|
||||||
|
return feliCaLookup2(rep, req, now);
|
||||||
|
|
||||||
case "lookup":
|
case "lookup":
|
||||||
return lookup(rep, req, now);
|
return lookup(rep, req, now);
|
||||||
|
|
||||||
@@ -124,7 +153,7 @@ export async function dispatch(
|
|||||||
return log(rep, req, now);
|
return log(rep, req, now);
|
||||||
|
|
||||||
case "goodbye":
|
case "goodbye":
|
||||||
console.log("Aimedb: Goodbye");
|
debug("Goodbye");
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
|
|||||||
+22
-17
@@ -1,39 +1,44 @@
|
|||||||
|
import logger from "debug";
|
||||||
import { Socket } from "net";
|
import { Socket } from "net";
|
||||||
|
|
||||||
import { dispatch } from "./handler";
|
import { dispatch } from "./handler";
|
||||||
import { AimeRequest } from "./request";
|
|
||||||
import { setup } from "./pipeline";
|
import { setup } from "./pipeline";
|
||||||
import { beginDbSession } from "./db";
|
import { DataSource } from "../sql/api";
|
||||||
|
import { SqlRepositories } from "./sql";
|
||||||
|
|
||||||
export default async function aimedb(socket: Socket) {
|
const debug = logger("app:aimedb:session");
|
||||||
console.log("Aimedb: Connection opened");
|
|
||||||
|
export default function aimedb(db: DataSource) {
|
||||||
|
return async function(socket: Socket) {
|
||||||
|
debug("Connection opened");
|
||||||
|
|
||||||
const { input, output } = setup(socket);
|
const { input, output } = setup(socket);
|
||||||
const txn = await beginDbSession();
|
|
||||||
|
|
||||||
try {
|
|
||||||
for await (const obj of input) {
|
for await (const obj of input) {
|
||||||
console.log("Aimedb: Decode", obj);
|
try {
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const req = obj as AimeRequest;
|
const req = obj;
|
||||||
const res = await dispatch(txn, req, now);
|
const res = await db.transaction(txn =>
|
||||||
|
dispatch(new SqlRepositories(txn), req, now)
|
||||||
|
);
|
||||||
|
|
||||||
if (res === undefined) {
|
if (res === undefined) {
|
||||||
console.log("Aimedb: Closing connection");
|
debug("Closing connection");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
output.write(res);
|
output.write(res);
|
||||||
}
|
|
||||||
|
|
||||||
await txn.commit();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Aimedb: Connection error:\n", e);
|
if (debug.enabled) {
|
||||||
await txn.rollback();
|
debug("Connection error: %s", e.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Aimedb: Connection closed\n");
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Connection closed");
|
||||||
socket.end();
|
socket.end();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as crypto from "crypto";
|
import { createCipheriv, createDecipheriv } from "crypto";
|
||||||
import { Socket } from "net";
|
import { Socket } from "net";
|
||||||
import * as stream from "stream";
|
import * as stream from "stream";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
@@ -26,7 +26,7 @@ export function setup(socket: Socket): Session {
|
|||||||
|
|
||||||
pipeline(
|
pipeline(
|
||||||
socket,
|
socket,
|
||||||
crypto.createDecipheriv("aes-128-ecb", K, null).setAutoPadding(false),
|
createDecipheriv("aes-128-ecb", K, null).setAutoPadding(false),
|
||||||
new Deframer({}),
|
new Deframer({}),
|
||||||
input
|
input
|
||||||
).catch(doNothing);
|
).catch(doNothing);
|
||||||
@@ -35,7 +35,7 @@ export function setup(socket: Socket): Session {
|
|||||||
|
|
||||||
pipeline(
|
pipeline(
|
||||||
output,
|
output,
|
||||||
crypto.createCipheriv("aes-128-ecb", K, null).setAutoPadding(false),
|
createCipheriv("aes-128-ecb", K, null).setAutoPadding(false),
|
||||||
socket
|
socket
|
||||||
).catch(doNothing);
|
).catch(doNothing);
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,3 @@ export interface CardRepository {
|
|||||||
export interface Repositories {
|
export interface Repositories {
|
||||||
cards(): CardRepository;
|
cards(): CardRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Transaction extends Repositories {
|
|
||||||
commit(): Promise<void>;
|
|
||||||
|
|
||||||
rollback(): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ export interface FeliCaLookupRequest extends AimeRequestBase {
|
|||||||
pmm: string;
|
pmm: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FeliCaLookup2Request extends AimeRequestBase {
|
||||||
|
type: "felica_lookup2";
|
||||||
|
idm: string;
|
||||||
|
pmm: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RegisterRequest extends AimeRequestBase {
|
export interface RegisterRequest extends AimeRequestBase {
|
||||||
type: "register";
|
type: "register";
|
||||||
luid: string;
|
luid: string;
|
||||||
@@ -50,6 +56,7 @@ export interface GoodbyeRequest {
|
|||||||
|
|
||||||
export type AimeRequest =
|
export type AimeRequest =
|
||||||
| FeliCaLookupRequest
|
| FeliCaLookupRequest
|
||||||
|
| FeliCaLookup2Request
|
||||||
| CampaignRequest
|
| CampaignRequest
|
||||||
| GoodbyeRequest
|
| GoodbyeRequest
|
||||||
| HelloRequest
|
| HelloRequest
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ export interface FeliCaLookupResponse extends AimeResponseBase {
|
|||||||
accessCode: string;
|
accessCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FeliCaLookup2Response extends AimeResponseBase {
|
||||||
|
type: "felica_lookup2";
|
||||||
|
accessCode: string;
|
||||||
|
aimeId?: AimeId;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CampaignResponse extends AimeResponseBase {
|
export interface CampaignResponse extends AimeResponseBase {
|
||||||
type: "campaign";
|
type: "campaign";
|
||||||
}
|
}
|
||||||
@@ -44,6 +50,7 @@ export interface RegisterResponse extends AimeResponseBase {
|
|||||||
|
|
||||||
export type AimeResponse =
|
export type AimeResponse =
|
||||||
| FeliCaLookupResponse
|
| FeliCaLookupResponse
|
||||||
|
| FeliCaLookup2Response
|
||||||
| CampaignResponse
|
| CampaignResponse
|
||||||
| HelloResponse
|
| HelloResponse
|
||||||
| LogResponse
|
| LogResponse
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import sql from "sql-bricks-postgres";
|
||||||
|
|
||||||
|
import { CardRepository, Repositories } from "./repo";
|
||||||
|
import { AimeId, generateExtId } from "../model";
|
||||||
|
import { Transaction } from "../sql";
|
||||||
|
|
||||||
|
class CardRepositoryImpl implements CardRepository {
|
||||||
|
constructor(private readonly _txn: Transaction) {}
|
||||||
|
|
||||||
|
async lookup(luid: string, now: Date): Promise<AimeId | undefined> {
|
||||||
|
const fetchSql = sql
|
||||||
|
.select("p.id", "p.ext_id")
|
||||||
|
.from("aime_player p")
|
||||||
|
.where("p.luid", luid);
|
||||||
|
|
||||||
|
const row = await this._txn.fetchRow(fetchSql);
|
||||||
|
|
||||||
|
if (row === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = row.id!;
|
||||||
|
const extId = row.ext_id!;
|
||||||
|
|
||||||
|
const touchSql = sql
|
||||||
|
.update("aime_player")
|
||||||
|
.set({ access_time: now })
|
||||||
|
.where("id", id);
|
||||||
|
|
||||||
|
await this._txn.modify(touchSql);
|
||||||
|
|
||||||
|
return parseInt(extId, 10) as AimeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async register(luid: string, now: Date): Promise<AimeId> {
|
||||||
|
const id = this._txn.generateId();
|
||||||
|
const aimeId = generateExtId() as AimeId;
|
||||||
|
|
||||||
|
const insertSql = sql.insert("aime_player", {
|
||||||
|
id: id,
|
||||||
|
ext_id: aimeId,
|
||||||
|
luid: luid,
|
||||||
|
register_time: now,
|
||||||
|
access_time: now,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this._txn.modify(insertSql);
|
||||||
|
|
||||||
|
return aimeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SqlRepositories implements Repositories {
|
||||||
|
constructor(private readonly _txn: Transaction) {}
|
||||||
|
|
||||||
|
cards(): CardRepository {
|
||||||
|
return new CardRepositoryImpl(this._txn);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-13
@@ -1,12 +1,13 @@
|
|||||||
import addHours = require("date-fns/add_hours");
|
import addHours from "date-fns/add_hours";
|
||||||
import express = require("express");
|
import express from "express";
|
||||||
import iconv = require("iconv-lite");
|
import iconv from "iconv-lite";
|
||||||
import read = require("raw-body");
|
import logger from "debug";
|
||||||
|
import read from "raw-body";
|
||||||
import { unzipSync } from "zlib";
|
import { unzipSync } from "zlib";
|
||||||
|
|
||||||
import { startupHost, startupUri } from "./switchboard";
|
import { startupHost, startupUri } from "./switchboard";
|
||||||
|
|
||||||
|
const debug = logger("app:allnet");
|
||||||
const hourDelta = parseInt(process.env.HOUR_DELTA || "0");
|
const hourDelta = parseInt(process.env.HOUR_DELTA || "0");
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@@ -58,8 +59,8 @@ app.use("/sys/servlet/PowerOn", async function(req, res, next) {
|
|||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/sys/servlet/PowerOn", function(req, resp) {
|
app.post("/sys/servlet/PowerOn", function(req, res) {
|
||||||
console.log("--- Startup Request ---\n\n", req.body);
|
debug("Startup request: %j", req.body);
|
||||||
|
|
||||||
// Cut milliseconds out of ISO timestamp
|
// Cut milliseconds out of ISO timestamp
|
||||||
|
|
||||||
@@ -73,14 +74,14 @@ app.post("/sys/servlet/PowerOn", function(req, resp) {
|
|||||||
uri: startupUri(req.body.game_id),
|
uri: startupUri(req.body.game_id),
|
||||||
host: startupHost(req.body.game_id),
|
host: startupHost(req.body.game_id),
|
||||||
place_id: "123",
|
place_id: "123",
|
||||||
name: process.env.SHOP_NAME,
|
name: process.env.SHOP_NAME || "",
|
||||||
nickname: process.env.SHOP_NAME,
|
nickname: process.env.SHOP_NAME || "",
|
||||||
region0: "1",
|
region0: "1",
|
||||||
region_name0: "W",
|
region_name0: "W",
|
||||||
region_name1: "X",
|
region_name1: "X",
|
||||||
region_name2: "Y",
|
region_name2: "Y",
|
||||||
region_name3: "Z",
|
region_name3: "Z",
|
||||||
country: process.env.SHOP_REGION,
|
country: process.env.SHOP_REGION || "JPN",
|
||||||
allnet_id: "456",
|
allnet_id: "456",
|
||||||
client_timezone: "+0900",
|
client_timezone: "+0900",
|
||||||
|
|
||||||
@@ -90,10 +91,9 @@ app.post("/sys/servlet/PowerOn", function(req, resp) {
|
|||||||
token: req.body.token,
|
token: req.body.token,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("\n--- Startup Response ---\n\n", resParams);
|
debug("Startup response: %j", resParams);
|
||||||
console.log("");
|
|
||||||
|
|
||||||
resp.send(resParams);
|
res.send(resParams);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
+6
-5
@@ -1,5 +1,6 @@
|
|||||||
import read = require("raw-body");
|
import express from "express";
|
||||||
import express = require("express");
|
import logger from "debug";
|
||||||
|
import read from "raw-body";
|
||||||
|
|
||||||
import { createSign } from "crypto";
|
import { createSign } from "crypto";
|
||||||
import { inflateRawSync } from "zlib";
|
import { inflateRawSync } from "zlib";
|
||||||
@@ -9,6 +10,7 @@ interface Kvps {
|
|||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const debug = logger("app:billing");
|
||||||
const billingKeyPair = readFileSync("pki/billing.key");
|
const billingKeyPair = readFileSync("pki/billing.key");
|
||||||
|
|
||||||
// nearfull: high 16 bits is billing mode, low 16 bits is actual nearfull val.
|
// nearfull: high 16 bits is billing mode, low 16 bits is actual nearfull val.
|
||||||
@@ -60,7 +62,7 @@ app.use(async function(req, res, next) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post("/request/", function(req, res) {
|
app.post("/request/", function(req, res) {
|
||||||
console.log("--- Billing Request ---\n\n", req.body);
|
debug("Billing request: %j", req.body);
|
||||||
|
|
||||||
const first = req.body[0];
|
const first = req.body[0];
|
||||||
|
|
||||||
@@ -133,8 +135,7 @@ app.post("/request/", function(req, res) {
|
|||||||
playhistory: "000000/0:000000/0:000000/0",
|
playhistory: "000000/0:000000/0:000000/0",
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("\n--- Billing Response ---\n\n", resItems);
|
debug("Billing response: %j", resItems);
|
||||||
console.log("");
|
|
||||||
|
|
||||||
res.set("content-type", "text/plain");
|
res.set("content-type", "text/plain");
|
||||||
res.send(resItems);
|
res.send(resItems);
|
||||||
|
|||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
import { readdirSync, readFileSync } from "fs";
|
||||||
|
import logger from "debug";
|
||||||
|
import { resolve } from "path";
|
||||||
|
import sql from "sql-bricks-postgres";
|
||||||
|
|
||||||
|
import { DataSource, Transaction } from "./sql";
|
||||||
|
|
||||||
|
const scripts = [
|
||||||
|
// Order matters! Later scripts reference schema instantiated earlier.
|
||||||
|
"meta.sql",
|
||||||
|
"aime.sql",
|
||||||
|
"cm.sql",
|
||||||
|
"idz.sql",
|
||||||
|
];
|
||||||
|
|
||||||
|
const debug = logger("app:checkdb");
|
||||||
|
const initPath = "./schema/init";
|
||||||
|
const migratePath = "./schema/migrate";
|
||||||
|
const migrateRx = new RegExp("^M([0-9]{4})-.+\\.sql$");
|
||||||
|
|
||||||
|
async function initdb(txn: Transaction): Promise<void> {
|
||||||
|
// Get latest schemaver from migration script filenames
|
||||||
|
|
||||||
|
const migrations = readdirSync(migratePath);
|
||||||
|
let schemaver = 0;
|
||||||
|
|
||||||
|
for (const filename of migrations) {
|
||||||
|
const captures = filename.match(migrateRx);
|
||||||
|
|
||||||
|
if (captures === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const migrationNo = parseInt(captures[1]);
|
||||||
|
|
||||||
|
if (schemaver < migrationNo) {
|
||||||
|
schemaver = migrationNo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run init scripts
|
||||||
|
|
||||||
|
debug("Initializing database");
|
||||||
|
|
||||||
|
for (const script of scripts) {
|
||||||
|
debug("Executing %s", script);
|
||||||
|
|
||||||
|
const scriptPath = resolve(initPath, script);
|
||||||
|
const scriptSql = readFileSync(scriptPath, "utf-8");
|
||||||
|
|
||||||
|
await txn.raw(scriptSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up metadata table
|
||||||
|
|
||||||
|
const metaInsert = sql.insert("meta", { schemaver });
|
||||||
|
|
||||||
|
await txn.modify(metaInsert);
|
||||||
|
|
||||||
|
debug("Initialized new database to schema version %s", schemaver);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migratedb(
|
||||||
|
txn: Transaction,
|
||||||
|
schemaver: number
|
||||||
|
): Promise<number | undefined> {
|
||||||
|
const filenames = readdirSync(migratePath);
|
||||||
|
let lastMigrationNo: number | undefined;
|
||||||
|
|
||||||
|
filenames.sort();
|
||||||
|
|
||||||
|
for (const filename of filenames) {
|
||||||
|
const captures = filename.match(migrateRx);
|
||||||
|
|
||||||
|
if (captures === null) {
|
||||||
|
debug("Warning: Unexpected file %s in SQL migrations dir", filename);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const migrationNo = parseInt(captures[1]);
|
||||||
|
|
||||||
|
if (migrationNo <= schemaver) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Executing database upgrade: %s", filename);
|
||||||
|
|
||||||
|
const scriptPath = resolve(migratePath, filename);
|
||||||
|
const scriptSql = readFileSync(scriptPath, "utf-8");
|
||||||
|
|
||||||
|
await txn.raw(scriptSql);
|
||||||
|
|
||||||
|
lastMigrationNo = migrationNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastMigrationNo !== undefined) {
|
||||||
|
const metaUpdate = sql.update("meta", { schemaver: lastMigrationNo });
|
||||||
|
|
||||||
|
await txn.modify(metaUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastMigrationNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function checkdb(db: DataSource): Promise<void> {
|
||||||
|
let schemaver: number | undefined;
|
||||||
|
|
||||||
|
await db.maintenance(async txn => {
|
||||||
|
const stmt = sql.select("schemaver").from("meta");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const row = await txn.fetchRow(stmt);
|
||||||
|
|
||||||
|
if (row !== undefined) {
|
||||||
|
schemaver = parseInt(row.schemaver!);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return await initdb(txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schemaver === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
"Database corrupted: `meta` table singleton row is missing"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
schemaver = await migratedb(txn, schemaver);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (schemaver !== undefined) {
|
||||||
|
debug("Upgraded database to version %s", schemaver);
|
||||||
|
|
||||||
|
await db.vacuum();
|
||||||
|
|
||||||
|
debug("Post-upgrade housekeeping complete");
|
||||||
|
}
|
||||||
|
}
|
||||||
-188
@@ -1,188 +0,0 @@
|
|||||||
import compression = require("compression");
|
|
||||||
import express = require("express");
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
|
|
||||||
// Thankfully we can use standard middleware for JSON I/O. We have to use a
|
|
||||||
// zlib middleware as well because compression is non-optional: the client will
|
|
||||||
// attempt to inflate whatever response we send to it whether there's a
|
|
||||||
// Transfer-Encoding header or not.
|
|
||||||
|
|
||||||
app.use(compression());
|
|
||||||
app.use(express.json());
|
|
||||||
|
|
||||||
// Trace requests and responses
|
|
||||||
|
|
||||||
app.use(function(req, resp, next) {
|
|
||||||
console.log("\n--- Chunithm %s ---\n", req.url);
|
|
||||||
console.log("Request:", req.body);
|
|
||||||
|
|
||||||
const prevJson = resp.json;
|
|
||||||
|
|
||||||
resp.json = function(obj) {
|
|
||||||
console.log("Response:", obj);
|
|
||||||
|
|
||||||
resp.json = prevJson;
|
|
||||||
resp.json.apply(this, arguments);
|
|
||||||
|
|
||||||
return resp;
|
|
||||||
};
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameSettingApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
gameSetting: {
|
|
||||||
dataVersion: 1,
|
|
||||||
isMaintenance: false,
|
|
||||||
requestInterval: 10,
|
|
||||||
rebootStartTime: 0,
|
|
||||||
rebootEndTime: 0,
|
|
||||||
isBackgroundDistribute: false,
|
|
||||||
maxCountCharacter: 999,
|
|
||||||
maxCountItem: 999,
|
|
||||||
maxCountMusic: 999,
|
|
||||||
},
|
|
||||||
isDumpUpload: false,
|
|
||||||
isAou: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/UpsertClientSettingApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
returnCode: 1,
|
|
||||||
apiName: "UpsertClientSettingApi",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/UpsertClientBookkeepingApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
returnCode: 1,
|
|
||||||
apiName: "UpsertClientBookkeepingApi",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/UpsertClientTestmodeApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
returnCode: 1,
|
|
||||||
apiName: "UpsertClientTestmodeApi",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/UpsertClientErrorApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
returnCode: 1,
|
|
||||||
apiName: "UpsertClientErrorApi",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/UpsertClientDevelopApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
returnCode: 1,
|
|
||||||
apiName: "UpsertClientDevelopApi",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameMessageApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
type: 1,
|
|
||||||
length: 0,
|
|
||||||
gameMessageList: [
|
|
||||||
/* {
|
|
||||||
type: 2,
|
|
||||||
id: 1,
|
|
||||||
message: "true",
|
|
||||||
startDate: "0",
|
|
||||||
endDate: "0"
|
|
||||||
},*/
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameIdlistApi", function(req, resp) {
|
|
||||||
const { type } = req.body;
|
|
||||||
|
|
||||||
resp.json({
|
|
||||||
type,
|
|
||||||
length: 0,
|
|
||||||
gameIdlistList: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameEventApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
type: 1,
|
|
||||||
length: 0,
|
|
||||||
gameEventList: [
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
type: 1,
|
|
||||||
id: 1102, // data/A000/event/event00001102
|
|
||||||
startDate: 'STRINGIDK',
|
|
||||||
endDate: 'STRINGIDK',
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameRankingApi", function(req, resp) {
|
|
||||||
const { type } = req.body;
|
|
||||||
|
|
||||||
resp.json({
|
|
||||||
type,
|
|
||||||
gameRankingList: [
|
|
||||||
/*
|
|
||||||
// QWORD fields maybe?
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
point: 1,
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameSaleApi", function(req, resp) {
|
|
||||||
const { type } = req.body;
|
|
||||||
|
|
||||||
resp.json({
|
|
||||||
type,
|
|
||||||
length: 0,
|
|
||||||
gameSaleList: [
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
orderId: 1234,
|
|
||||||
type,
|
|
||||||
id: 4321,
|
|
||||||
rate: 5678,
|
|
||||||
startDate: 'STRINGIDK',
|
|
||||||
endDate: 'STRINGIDK',
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/ChuniServlet/GetGameChargeApi", function(req, resp) {
|
|
||||||
resp.json({
|
|
||||||
length: 0,
|
|
||||||
gameChargeList: [
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
orderId: 1,
|
|
||||||
chargeId: 1,
|
|
||||||
price: 1,
|
|
||||||
startDate: 'STRINGIDK',
|
|
||||||
endDate: 'STRINGIDK',
|
|
||||||
salePrice:
|
|
||||||
saleStartDate: 'STRINGIDK',
|
|
||||||
saleEndDate: 'STRINGIDK',
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export default app;
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Make the names explicit so that we don't get the order mixed up
|
||||||
|
interface Params {
|
||||||
|
maxCount: number;
|
||||||
|
nextIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function paginationCookie<T>(items: T[], params: Params) {
|
||||||
|
if (items.length < params.maxCount) {
|
||||||
|
return "-1";
|
||||||
|
} else {
|
||||||
|
return (params.nextIndex + params.maxCount).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GameLoginRequest } from "../request/gameLogin";
|
||||||
|
import { GameLoginResponse } from "../response/gameLogin";
|
||||||
|
|
||||||
|
export default async function gameLogin(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GameLoginRequest
|
||||||
|
): Promise<GameLoginResponse> {
|
||||||
|
return { returnCode: "1" };
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GameLogoutRequest } from "../request/gameLogout";
|
||||||
|
import { GameLogoutResponse } from "../response/gameLogout";
|
||||||
|
|
||||||
|
export default async function gameLogout(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GameLogoutRequest
|
||||||
|
): Promise<GameLogoutResponse> {
|
||||||
|
return { returnCode: "1" };
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { GameChargeJson } from "../proto/gameCharge";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameChargeRequest } from "../request/getGameCharge";
|
||||||
|
import { GetGameChargeResponse } from "../response/getGameCharge";
|
||||||
|
import { CHARGE_IDS } from "../static/charge";
|
||||||
|
|
||||||
|
export default async function getGameCharge(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameChargeRequest
|
||||||
|
): Promise<GetGameChargeResponse> {
|
||||||
|
const gameChargeList: GameChargeJson[] = [];
|
||||||
|
|
||||||
|
for (const [i, charge] of CHARGE_IDS.entries()) {
|
||||||
|
gameChargeList.push({
|
||||||
|
chargeId: charge.id.toString(),
|
||||||
|
orderId: (i+1).toString(),
|
||||||
|
price: charge.price.toString(),
|
||||||
|
salePrice: charge.salePrice.toString(),
|
||||||
|
startDate: "2017-12-05 07:00:00.0",
|
||||||
|
endDate: "2029-12-31 23:59:59.0",
|
||||||
|
saleStartDate: "2017-12-05 07:00:00.0",
|
||||||
|
saleEndDate: "2030-12-31 23:59:59.0"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
length: gameChargeList.length.toString(),
|
||||||
|
gameChargeList,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { GameEventJson } from "../proto/gameEvent";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameEventRequest } from "../request/getGameEvent";
|
||||||
|
import { GetGameEventResponse } from "../response/getGameEvent";
|
||||||
|
import { EVENT_IDS } from "../static/event";
|
||||||
|
|
||||||
|
export default async function getGameEvent(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameEventRequest
|
||||||
|
): Promise<GetGameEventResponse> {
|
||||||
|
const gameEventList: GameEventJson[] = [];
|
||||||
|
|
||||||
|
for (const id of EVENT_IDS) {
|
||||||
|
gameEventList.push({
|
||||||
|
type: req.type,
|
||||||
|
id: id.toString(),
|
||||||
|
startDate: "2017-12-05 07:00:00.0",
|
||||||
|
endDate: "2099-12-31 00:00:00.0",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: req.type,
|
||||||
|
length: gameEventList.length.toString(),
|
||||||
|
gameEventList,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameIdlistRequest } from "../request/getGameIdlist";
|
||||||
|
import { GetGameIdlistResponse } from "../response/getGameIdlist";
|
||||||
|
|
||||||
|
export default async function getGameIdlist(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameIdlistRequest
|
||||||
|
): Promise<GetGameIdlistResponse> {
|
||||||
|
return {
|
||||||
|
type: req.type,
|
||||||
|
length: "0",
|
||||||
|
gameIdlistList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameMessageRequest } from "../request/getGameMessage";
|
||||||
|
import { GetGameMessageResponse } from "../response/getGameMessage";
|
||||||
|
|
||||||
|
export default async function getGameMessage(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameMessageRequest
|
||||||
|
): Promise<GetGameMessageResponse> {
|
||||||
|
return {
|
||||||
|
type: req.type,
|
||||||
|
length: "0",
|
||||||
|
gameMessageList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameRankingRequest } from "../request/getGameRanking";
|
||||||
|
import { GetGameRankingResponse } from "../response/getGameRanking";
|
||||||
|
|
||||||
|
export default async function getGameRanking(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameRankingRequest
|
||||||
|
): Promise<GetGameRankingResponse> {
|
||||||
|
return {
|
||||||
|
type: req.type,
|
||||||
|
gameRankingList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameSaleRequest } from "../request/getGameSale";
|
||||||
|
import { GetGameSaleResponse } from "../response/getGameSale";
|
||||||
|
|
||||||
|
export default async function getGameSale(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameSaleRequest
|
||||||
|
): Promise<GetGameSaleResponse> {
|
||||||
|
return {
|
||||||
|
type: req.type,
|
||||||
|
length: "0",
|
||||||
|
gameSaleList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { writeDate } from "../proto/base";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetGameSettingRequest } from "../request/getGameSetting";
|
||||||
|
import { GetGameSettingResponse } from "../response/getGameSetting";
|
||||||
|
|
||||||
|
export default async function getGameSetting(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetGameSettingRequest
|
||||||
|
): Promise<GetGameSettingResponse> {
|
||||||
|
const rebootStartTime = new Date();
|
||||||
|
rebootStartTime.setHours(rebootStartTime.getHours() - 3);
|
||||||
|
|
||||||
|
const rebootEndTime = new Date();
|
||||||
|
rebootEndTime.setHours(rebootEndTime.getHours() - 2);
|
||||||
|
|
||||||
|
return {
|
||||||
|
gameSetting: {
|
||||||
|
dataVersion: "1",
|
||||||
|
isMaintenance: "false",
|
||||||
|
requestInterval: "10",
|
||||||
|
rebootStartTime: writeDate(rebootStartTime),
|
||||||
|
rebootEndTime: writeDate(rebootEndTime),
|
||||||
|
isBackgroundDistribute: "false",
|
||||||
|
maxCountCharacter: "300",
|
||||||
|
maxCountItem: "300",
|
||||||
|
maxCountMusic: "100",
|
||||||
|
},
|
||||||
|
isDumpUpload: "false",
|
||||||
|
isAou: "true",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserActivity } from "../proto/userActivity";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserActivityRequest } from "../request/getUserActivity";
|
||||||
|
import { GetUserActivityResponse } from "../response/getUserActivity";
|
||||||
|
|
||||||
|
export default async function getUserActivity(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserActivityRequest
|
||||||
|
): Promise<GetUserActivityResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const kind = parseInt(req.kind);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const items = await rep.userActivity().load(profileId, kind);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
kind: kind.toString(),
|
||||||
|
userActivityList: items.map(writeUserActivity),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { paginationCookie } from "./_util";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserCharacter } from "../proto/userCharacter";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserCharacterRequest } from "../request/getUserCharacter";
|
||||||
|
import { GetUserCharacterResponse } from "../response/getUserCharacter";
|
||||||
|
|
||||||
|
export default async function getUserCharacter(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserCharacterRequest
|
||||||
|
): Promise<GetUserCharacterResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const maxCount = parseInt(req.maxCount);
|
||||||
|
const nextIndex = parseInt(req.nextIndex);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const items = await rep
|
||||||
|
.userCharacter()
|
||||||
|
.load(profileId, { limit: maxCount, offset: nextIndex });
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
nextIndex: paginationCookie(items, { maxCount, nextIndex }),
|
||||||
|
userCharacterList: items.map(writeUserCharacter),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserCharge } from "../proto/userCharge";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserChargeRequest } from "../request/getUserCharge";
|
||||||
|
import { GetUserChargeResponse } from "../response/getUserCharge";
|
||||||
|
|
||||||
|
export default async function getUserCharge(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserChargeRequest
|
||||||
|
): Promise<GetUserChargeResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const items = await rep.userCharge().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
userChargeList: items.map(writeUserCharge),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserCourseRequest } from "../request/getUserCourse";
|
||||||
|
import { GetUserCourseResponse } from "../response/getUserCourse";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { paginationCookie } from "./_util";
|
||||||
|
import { writeUserCourse } from "../proto/userCourse";
|
||||||
|
|
||||||
|
export default async function getUserCourse(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserCourseRequest
|
||||||
|
): Promise<GetUserCourseResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const maxCount = parseInt(req.maxCount);
|
||||||
|
const nextIndex = parseInt(req.nextIndex);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const items = await rep
|
||||||
|
.userCourse()
|
||||||
|
.load(profileId, { limit: maxCount, offset: nextIndex });
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
nextIndex: paginationCookie(items, { maxCount, nextIndex }),
|
||||||
|
userCourseList: items.map(writeUserCourse)
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserData } from "../proto/userData";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserDataRequest } from "../request/getUserData";
|
||||||
|
import { GetUserDataResponse } from "../response/getUserData";
|
||||||
|
|
||||||
|
export default async function getUserData(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserDataRequest
|
||||||
|
): Promise<GetUserDataResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const userData = await rep.userData().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
userData: writeUserData(userData),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserDataEx } from "../proto/userDataEx";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserDataExRequest } from "../request/getUserDataEx";
|
||||||
|
import { GetUserDataExResponse } from "../response/getUserDataEx";
|
||||||
|
|
||||||
|
export default async function getUserDataEx(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserDataExRequest
|
||||||
|
): Promise<GetUserDataExResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const userDataEx = await rep.userDataEx().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
userDataEx: writeUserDataEx(userDataEx),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserDuelRequest } from "../request/getUserDuel";
|
||||||
|
import { GetUserDuelResponse } from "../response/getUserDuel";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserDuelList } from "../proto/userDuelList";
|
||||||
|
|
||||||
|
export default async function getUserDuel(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserDuelRequest
|
||||||
|
): Promise<GetUserDuelResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
// Get all duel entities if the client specifies to.
|
||||||
|
const duelId = req.isAllDuel ? undefined : parseInt(req.duelId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const items = await rep.userDuelList().load(profileId, duelId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
userDuelList: items.map(writeUserDuelList),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserFavoriteMusicRequest } from "../request/getUserFavoriteMusic";
|
||||||
|
import { GetUserFavoriteMusicResponse } from "../response/getUserFavoriteMusic";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
|
||||||
|
export default async function getUserFavoriteMusic(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserFavoriteMusicRequest
|
||||||
|
): Promise<GetUserFavoriteMusicResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `Chunithm Amazon Plus` does not appear to save a favorites list and there
|
||||||
|
* is no user-accessible favorites function from what I can tell.
|
||||||
|
*/
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: "0",
|
||||||
|
userFavoriteMusicList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserItem } from "../proto/userItem";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserItemRequest } from "../request/getUserItem";
|
||||||
|
import { GetUserItemResponse } from "../response/getUserItem";
|
||||||
|
import { UserItemItem } from "../model/userItem";
|
||||||
|
|
||||||
|
// I'm not sure why they went to all this trouble just to avoid passing an
|
||||||
|
// explicit `itemKind` parameter in the request...
|
||||||
|
|
||||||
|
const itemKindMul = 10000000000n;
|
||||||
|
|
||||||
|
export default async function getUserItem(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserItemRequest
|
||||||
|
): Promise<GetUserItemResponse> {
|
||||||
|
// Split the "nextIndex" parameter
|
||||||
|
|
||||||
|
const compoundIn = BigInt(req.nextIndex);
|
||||||
|
const itemKindN = compoundIn / itemKindMul;
|
||||||
|
const nextIndexN = compoundIn % itemKindMul;
|
||||||
|
|
||||||
|
// Now unpack the entire request
|
||||||
|
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const maxCount = parseInt(req.maxCount);
|
||||||
|
const itemKind = parseInt(itemKindN as any);
|
||||||
|
const nextIndex = parseInt(nextIndexN as any);
|
||||||
|
|
||||||
|
// Hit DB
|
||||||
|
// This gets called for not-yet-created profiles for some reason (probably
|
||||||
|
// so that the server can force some bonus items into a new profile's
|
||||||
|
// inventory)? So we need to gracefully handle that condition.
|
||||||
|
|
||||||
|
// (maybe some sort of anchor row is created on first GameLogin...)
|
||||||
|
|
||||||
|
const profileId = await rep.userData().tryLookup(aimeId);
|
||||||
|
let items: UserItemItem[];
|
||||||
|
|
||||||
|
if (profileId !== undefined) {
|
||||||
|
items = await rep
|
||||||
|
.userItem()
|
||||||
|
.load(profileId, itemKind, { limit: maxCount, offset: nextIndex });
|
||||||
|
} else {
|
||||||
|
items = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack the next pagination cookie into bigint compound form
|
||||||
|
|
||||||
|
const xout = itemKindN * itemKindMul + nextIndexN + BigInt(items.length);
|
||||||
|
|
||||||
|
// Done:
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
nextIndex: items.length < maxCount ? "-1" : xout.toString(),
|
||||||
|
itemKind: itemKind.toString(),
|
||||||
|
userItemList: items.map(writeUserItem),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserMap } from "../proto/userMap";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserMapRequest } from "../request/getUserMap";
|
||||||
|
import { GetUserMapResponse } from "../response/getUserMap";
|
||||||
|
|
||||||
|
export default async function getUserMap(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserMapRequest
|
||||||
|
): Promise<GetUserMapResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const items = await rep.userMap().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
userMapList: items.map(writeUserMap),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { writeUserMusicDetail, UserMusicJson } from "../proto/userMusic";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserMusicRequest } from "../request/getUserMusic";
|
||||||
|
import { GetUserMusicResponse } from "../response/getUserMusic";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { UserMusicDetailItem } from "../model/userMusic";
|
||||||
|
import { paginationCookie } from "./_util";
|
||||||
|
|
||||||
|
export default async function getUserMusic(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserMusicRequest
|
||||||
|
): Promise<GetUserMusicResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const maxCount = parseInt(req.maxCount);
|
||||||
|
const nextIndex = parseInt(req.nextIndex);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const flat = await rep
|
||||||
|
.userMusic()
|
||||||
|
.load(profileId, { limit: maxCount, offset: nextIndex });
|
||||||
|
|
||||||
|
const groupIdx = new Map<number, UserMusicDetailItem[]>();
|
||||||
|
|
||||||
|
for (const item of flat) {
|
||||||
|
const { musicId } = item;
|
||||||
|
const existing = groupIdx.get(musicId);
|
||||||
|
|
||||||
|
if (existing !== undefined) {
|
||||||
|
existing.push(item);
|
||||||
|
} else {
|
||||||
|
groupIdx.set(musicId, [item]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const userMusicList = new Array<UserMusicJson>();
|
||||||
|
|
||||||
|
for (const group of groupIdx.values()) {
|
||||||
|
userMusicList.push({
|
||||||
|
length: group.length.toString(),
|
||||||
|
userMusicDetailList: group.map(writeUserMusicDetail),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: userMusicList.length.toString(),
|
||||||
|
nextIndex: paginationCookie(flat, { maxCount, nextIndex }),
|
||||||
|
userMusicList,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserGameOption } from "../proto/userGameOption";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserOptionRequest } from "../request/getUserOption";
|
||||||
|
import { GetUserOptionResponse } from "../response/getUserOption";
|
||||||
|
|
||||||
|
export default async function getUserOption(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserOptionRequest
|
||||||
|
): Promise<GetUserOptionResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const userGameOption = await rep.userGameOption().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
userGameOption: writeUserGameOption(userGameOption),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserGameOptionEx } from "../proto/userGameOptionEx";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserOptionExRequest } from "../request/getUserOptionEx";
|
||||||
|
import { GetUserOptionExResponse } from "../response/getUserOptionEx";
|
||||||
|
|
||||||
|
export default async function getUserOptionEx(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserOptionExRequest
|
||||||
|
): Promise<GetUserOptionExResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
const userGameOptionEx = await rep.userGameOptionEx().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
userGameOptionEx: writeUserGameOptionEx(userGameOptionEx),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { readAimeId, writeDate } from "../proto/base";
|
||||||
|
import { writeUserCharacter } from "../proto/userCharacter";
|
||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserPreviewRequest } from "../request/getUserPreview";
|
||||||
|
import { GetUserPreviewResponse } from "../response/getUserPreview";
|
||||||
|
|
||||||
|
export default async function getUserPreview(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserPreviewRequest
|
||||||
|
): Promise<GetUserPreviewResponse | null> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const profileId = await rep.userData().tryLookup(aimeId);
|
||||||
|
|
||||||
|
// Return an empty JSON object if the player lacks a profile; this will
|
||||||
|
// start the new profile registration flow in the client.
|
||||||
|
|
||||||
|
if (profileId === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userData = await rep.userData().load(profileId);
|
||||||
|
const userCharacter = await rep
|
||||||
|
.userCharacter()
|
||||||
|
.loadOne(profileId, userData.characterId);
|
||||||
|
const userGameOption = await rep.userGameOption().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: "1",
|
||||||
|
|
||||||
|
// Current login (i.e. profile lock) status
|
||||||
|
|
||||||
|
isLogin: "false",
|
||||||
|
lastLoginDate: "1970-01-01 09:00:00",
|
||||||
|
|
||||||
|
// UserData:
|
||||||
|
|
||||||
|
userName: userData.userName,
|
||||||
|
reincarnationNum: userData.reincarnationNum.toString(),
|
||||||
|
level: userData.level.toString(),
|
||||||
|
exp: userData.exp.toString(),
|
||||||
|
playerRating: userData.playerRating.toString(),
|
||||||
|
lastGameId: userData.lastGameId,
|
||||||
|
lastRomVersion: userData.lastRomVersion,
|
||||||
|
lastDataVersion: userData.lastDataVersion,
|
||||||
|
lastPlayDate: writeDate(userData.lastPlayDate),
|
||||||
|
trophyId: userData.trophyId.toString(),
|
||||||
|
|
||||||
|
// Currently selected UserCharacter:
|
||||||
|
|
||||||
|
userCharacter: writeUserCharacter(userCharacter),
|
||||||
|
|
||||||
|
// UserGameOption:
|
||||||
|
|
||||||
|
playerLevel: userGameOption.playerLevel.toString(),
|
||||||
|
rating: userGameOption.rating.toString(),
|
||||||
|
headphone: userGameOption.headphone.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserRecentRatingRequest } from "../request/getUserRecentRating";
|
||||||
|
import { GetUserRecentRatingResponse } from "../response/getUserRecentRating";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { writeUserRecentRating } from "../proto/userRecentRating";
|
||||||
|
|
||||||
|
export default async function getUserRecentRating(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserRecentRatingRequest
|
||||||
|
): Promise<GetUserRecentRatingResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().lookup(aimeId);
|
||||||
|
// Return recent 30 plays to calculate rating
|
||||||
|
const items = await rep.userRecentRating().load(profileId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: items.length.toString(),
|
||||||
|
userRecentRatingList: items.map(writeUserRecentRating),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { GetUserRegionRequest } from "../request/getUserRegion";
|
||||||
|
import { GetUserRegionResponse } from "../response/getUserRegion";
|
||||||
|
|
||||||
|
export default async function getUserRegion(
|
||||||
|
rep: Repositories,
|
||||||
|
req: GetUserRegionRequest
|
||||||
|
): Promise<GetUserRegionResponse> {
|
||||||
|
return {
|
||||||
|
userId: req.userId,
|
||||||
|
length: "0",
|
||||||
|
userRegionList: [
|
||||||
|
// Doesn't get saved
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import compression from "compression";
|
||||||
|
import express, { NextFunction, Request, Response } from "express";
|
||||||
|
import logger from "debug";
|
||||||
|
|
||||||
|
import gameLogin from "./gameLogin";
|
||||||
|
import gameLogout from "./gameLogout";
|
||||||
|
import getGameCharge from "./getGameCharge";
|
||||||
|
import getGameEvent from "./getGameEvent";
|
||||||
|
import getGameIdlist from "./getGameIdlist";
|
||||||
|
import getGameMessage from "./getGameMessage";
|
||||||
|
import getGameRanking from "./getGameRanking";
|
||||||
|
import getGameSale from "./getGameSale";
|
||||||
|
import getGameSetting from "./getGameSetting";
|
||||||
|
import getUserActivity from "./getUserActivity";
|
||||||
|
import getUserCharacter from "./getUserCharacter";
|
||||||
|
import getUserCharge from "./getUserCharge";
|
||||||
|
import getUserCourse from "./getUserCourse";
|
||||||
|
import getUserData from "./getUserData";
|
||||||
|
import getUserDataEx from "./getUserDataEx";
|
||||||
|
import getUserDuel from "./getUserDuel";
|
||||||
|
import getUserFavoriteMusic from "./getUserFavoriteMusic";
|
||||||
|
import getUserItem from "./getUserItem";
|
||||||
|
import getUserMap from "./getUserMap";
|
||||||
|
import getUserMusic from "./getUserMusic";
|
||||||
|
import getUserOption from "./getUserOption";
|
||||||
|
import getUserOptionEx from "./getUserOptionEx";
|
||||||
|
import getUserPreview from "./getUserPreview";
|
||||||
|
import getUserRecentRating from "./getUserRecentRating";
|
||||||
|
import getUserRegion from "./getUserRegion";
|
||||||
|
import upsertClientBookkeeping from "./upsertClientBookkeeping";
|
||||||
|
import upsertClientDevelop from "./upsertClientDevelop";
|
||||||
|
import upsertClientError from "./upsertClientError";
|
||||||
|
import upsertClientSetting from "./upsertClientSetting";
|
||||||
|
import upsertClientTestmode from "./upsertClientTestmode";
|
||||||
|
import upsertUserAll from "./upsertUserAll";
|
||||||
|
import upsertUserChargelogApi from "./upsertUserChargelogApi";
|
||||||
|
import createSqlWrapper from "../sql";
|
||||||
|
import { DataSource } from "../../sql";
|
||||||
|
|
||||||
|
const debug = logger("app:chuni:io");
|
||||||
|
|
||||||
|
// Thankfully we can use standard middleware for JSON I/O. We have to use a
|
||||||
|
// zlib middleware as well because compression is non-optional: the client will
|
||||||
|
// attempt to inflate whatever response we send to it whether there's a
|
||||||
|
// Transfer-Encoding header or not.
|
||||||
|
|
||||||
|
function quirks(req: Request, res: Response, next: NextFunction) {
|
||||||
|
// Chunithm client does not follow the HTTP spec: user agents must indicate
|
||||||
|
// that they are willing to accept a particular Transfer-Encoding for that
|
||||||
|
// T-E to be used (unless the T-E in question is "chunked" but w/e), and this
|
||||||
|
// indication is advisory anyway, the server is permitted to ignore it.
|
||||||
|
//
|
||||||
|
// Force this header into the request, since it is not present normally.
|
||||||
|
|
||||||
|
// ... unless, that is, the client is actually somebody debugging with curl
|
||||||
|
// and not the real game client, in which case this forced deflate can be
|
||||||
|
// annoying. Pass an "X-Debug" request header to suppress forced compression.
|
||||||
|
|
||||||
|
if (req.headers["x-debug"] === undefined) {
|
||||||
|
req.headers["accept-encoding"] = "deflate";
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
function trace(req: Request, res: Response, next: NextFunction) {
|
||||||
|
debug("\n--- Chunithm %s ---\n", req.url);
|
||||||
|
debug("Request: %j", req.body);
|
||||||
|
|
||||||
|
const prevJson = res.json;
|
||||||
|
|
||||||
|
res.json = function(obj) {
|
||||||
|
debug("Response: %j", obj);
|
||||||
|
|
||||||
|
res.json = prevJson;
|
||||||
|
res.json.apply(this, arguments);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function chunithm(db: DataSource) {
|
||||||
|
const wrapper = createSqlWrapper(db);
|
||||||
|
|
||||||
|
wrapper.rpc("/GameLoginApi", gameLogin);
|
||||||
|
wrapper.rpc("/GameLogoutApi", gameLogout);
|
||||||
|
wrapper.rpc("/GetGameChargeApi", getGameCharge);
|
||||||
|
wrapper.rpc("/GetGameEventApi", getGameEvent);
|
||||||
|
wrapper.rpc("/GetGameIdlistApi", getGameIdlist);
|
||||||
|
wrapper.rpc("/GetGameMessageApi", getGameMessage);
|
||||||
|
wrapper.rpc("/GetGameRankingApi", getGameRanking);
|
||||||
|
wrapper.rpc("/GetGameSaleApi", getGameSale);
|
||||||
|
wrapper.rpc("/GetGameSettingApi", getGameSetting);
|
||||||
|
wrapper.rpc("/GetUserActivityApi", getUserActivity);
|
||||||
|
wrapper.rpc("/GetUserCharacterApi", getUserCharacter);
|
||||||
|
wrapper.rpc("/GetUserChargeApi", getUserCharge);
|
||||||
|
wrapper.rpc("/GetUserCourseAPi", getUserCourse);
|
||||||
|
wrapper.rpc("/GetUserDataApi", getUserData);
|
||||||
|
wrapper.rpc("/GetUserDataExApi", getUserDataEx);
|
||||||
|
wrapper.rpc("/GetUserDuelApi", getUserDuel);
|
||||||
|
wrapper.rpc("/GetUserFavoriteMusicApi", getUserFavoriteMusic);
|
||||||
|
wrapper.rpc("/GetUserItemApi", getUserItem);
|
||||||
|
wrapper.rpc("/GetUserMapApi", getUserMap);
|
||||||
|
wrapper.rpc("/GetUserMusicApi", getUserMusic);
|
||||||
|
wrapper.rpc("/GetUserOptionApi", getUserOption);
|
||||||
|
wrapper.rpc("/GetUserOptionExApi", getUserOptionEx);
|
||||||
|
wrapper.rpc("/GetUserPreviewApi", getUserPreview);
|
||||||
|
wrapper.rpc("/GetUserRecentPlayerApi", getUserRecentRating);
|
||||||
|
wrapper.rpc("/GetUserRecentRatingApi", getUserRecentRating);
|
||||||
|
wrapper.rpc("/GetUserRegionApi", getUserRegion);
|
||||||
|
wrapper.rpc("/UpsertClientBookkeepingApi", upsertClientBookkeeping);
|
||||||
|
wrapper.rpc("/UpsertClientDevelopApi", upsertClientDevelop);
|
||||||
|
wrapper.rpc("/UpsertClientErrorApi", upsertClientError);
|
||||||
|
wrapper.rpc("/UpsertClientSettingApi", upsertClientSetting);
|
||||||
|
wrapper.rpc("/UpsertClientTestmodeApi", upsertClientTestmode);
|
||||||
|
wrapper.rpc("/UpsertUserAllApi", upsertUserAll);
|
||||||
|
wrapper.rpc("/UpsertUserChargelogApi", upsertUserChargelogApi)
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(quirks);
|
||||||
|
app.use(compression({ threshold: 0 }));
|
||||||
|
app.use(express.json({ limit: "50mb" })); // that ought to be enough
|
||||||
|
app.use(trace);
|
||||||
|
|
||||||
|
app.use("/ChuniServlet", wrapper);
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { UpsertClientBookkeepingRequest } from "../request/upsertClientBookkeeping";
|
||||||
|
import { UpsertClientBookkeepingResponse } from "../response/upsertClientBookkeeping";
|
||||||
|
|
||||||
|
export default async function upsertClientBookkeeping(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertClientBookkeepingRequest
|
||||||
|
): Promise<UpsertClientBookkeepingResponse> {
|
||||||
|
return {
|
||||||
|
returnCode: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { UpsertClientDevelopRequest } from "../request/upsertClientDevelop";
|
||||||
|
import { UpsertClientDevelopResponse } from "../response/upsertClientDevelop";
|
||||||
|
|
||||||
|
export default async function upsertClientDevelop(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertClientDevelopRequest
|
||||||
|
): Promise<UpsertClientDevelopResponse> {
|
||||||
|
return {
|
||||||
|
returnCode: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { UpsertClientErrorRequest } from "../request/upsertClientError";
|
||||||
|
import { UpsertClientErrorResponse } from "../response/upsertClientError";
|
||||||
|
|
||||||
|
export default async function upsertClientError(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertClientErrorRequest
|
||||||
|
): Promise<UpsertClientErrorResponse> {
|
||||||
|
return {
|
||||||
|
returnCode: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { UpsertClientSettingRequest } from "../request/upsertClientSetting";
|
||||||
|
import { UpsertClientSettingResponse } from "../response/upsertClientSetting";
|
||||||
|
|
||||||
|
export default async function upsertClientSetting(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertClientSettingRequest
|
||||||
|
): Promise<UpsertClientSettingResponse> {
|
||||||
|
return {
|
||||||
|
returnCode: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { UpsertClientTestmodeRequest } from "../request/upsertClientTestmode";
|
||||||
|
import { UpsertClientTestmodeResponse } from "../response/upsertClientTestmode";
|
||||||
|
|
||||||
|
export default async function upsertClientTestmode(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertClientTestmodeRequest
|
||||||
|
): Promise<UpsertClientTestmodeResponse> {
|
||||||
|
return {
|
||||||
|
returnCode: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { readAimeId } from "../proto/base";
|
||||||
|
import { readUserCharacter } from "../proto/userCharacter";
|
||||||
|
import { readUserData } from "../proto/userData";
|
||||||
|
import { readUserGameOption } from "../proto/userGameOption";
|
||||||
|
import { UpsertUserAllRequest } from "../request/upsertUserAll";
|
||||||
|
import { UpsertUserAllResponse } from "../response/upsertUserAll";
|
||||||
|
import { readUserGameOptionEx } from "../proto/userGameOptionEx";
|
||||||
|
import { readUserMap } from "../proto/userMap";
|
||||||
|
import { readUserItem } from "../proto/userItem";
|
||||||
|
import { readUserMusicDetail } from "../proto/userMusic";
|
||||||
|
import { readUserActivity } from "../proto/userActivity";
|
||||||
|
import { readUserDataEx } from "../proto/userDataEx";
|
||||||
|
import { readUserDuelList } from "../proto/userDuelList";
|
||||||
|
import { readUserPlaylog } from "../proto/userPlaylog";
|
||||||
|
import { readUserCharge } from "../proto/userCharge";
|
||||||
|
import { readUserRecentRating } from "../proto/userRecentRating";
|
||||||
|
import { readUserCourse } from "../proto/userCourse";
|
||||||
|
|
||||||
|
// It shouldn't need to be said really, but seeing as this message (A) requires
|
||||||
|
// fairly lengthy processing and (B) is only sent right at the end of a credit,
|
||||||
|
// you should probably copy the JSON from the server's debug log and then
|
||||||
|
// validate this implementation using curl if you're planning to make any
|
||||||
|
// modifications to how things get saved.
|
||||||
|
|
||||||
|
export default async function upsertUserAll(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertUserAllRequest
|
||||||
|
): Promise<UpsertUserAllResponse> {
|
||||||
|
const aimeId = readAimeId(req.userId);
|
||||||
|
const payload = req.upsertUserAll;
|
||||||
|
const profile = readUserData(req.upsertUserAll.userData[0]);
|
||||||
|
|
||||||
|
const profileId = await rep.userData().save(aimeId, profile);
|
||||||
|
|
||||||
|
// Empty lists don't get sent at all. Not sure which are potentially empty
|
||||||
|
// so let's just assume the answer is "all of them". Hence the use of || []
|
||||||
|
// everywhere.
|
||||||
|
|
||||||
|
for (const item of payload.userGameOption || []) {
|
||||||
|
await rep.userGameOption().save(profileId, readUserGameOption(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userGameOptionEx || []) {
|
||||||
|
await rep.userGameOptionEx().save(profileId, readUserGameOptionEx(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userMapList || []) {
|
||||||
|
await rep.userMap().save(profileId, readUserMap(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userCharacterList || []) {
|
||||||
|
await rep.userCharacter().save(profileId, readUserCharacter(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userItemList || []) {
|
||||||
|
await rep.userItem().save(profileId, readUserItem(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userMusicDetailList || []) {
|
||||||
|
await rep.userMusic().save(profileId, readUserMusicDetail(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userActivityList || []) {
|
||||||
|
await rep.userActivity().save(profileId, readUserActivity(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userPlaylogList || []) {
|
||||||
|
await rep.userPlaylog().save(profileId, readUserPlaylog(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userChargeList || []) {
|
||||||
|
await rep.userCharge().save(profileId, readUserCharge(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userCourseList || []) {
|
||||||
|
await rep.userCourse().save(profileId, readUserCourse(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userDataEx || []) {
|
||||||
|
await rep.userDataEx().save(profileId, readUserDataEx(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of payload.userDuelList || []) {
|
||||||
|
await rep.userDuelList().save(profileId, readUserDuelList(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
await rep
|
||||||
|
.userRecentRating()
|
||||||
|
.save(
|
||||||
|
profileId,
|
||||||
|
(payload.userRecentRatingList || []).map(readUserRecentRating)
|
||||||
|
);
|
||||||
|
|
||||||
|
return { returnCode: "1" };
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Repositories } from "../repo";
|
||||||
|
import { UpsertUserChargelogApiRequest } from "../request/upsertUserChargelogApi";
|
||||||
|
import { UpsertUserChargelogApiResponse } from "../response/upsertUserChargelogApi";
|
||||||
|
|
||||||
|
export default async function UpsertUserChargelogApi(
|
||||||
|
rep: Repositories,
|
||||||
|
req: UpsertUserChargelogApiRequest
|
||||||
|
): Promise<UpsertUserChargelogApiResponse> {
|
||||||
|
return {
|
||||||
|
returnCode: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import chunithm from "./handler";
|
||||||
|
export default chunithm;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export interface GameChargeItem {
|
||||||
|
orderId: number;
|
||||||
|
chargeId: number;
|
||||||
|
price: number;
|
||||||
|
startDate: Date;
|
||||||
|
endDate: Date;
|
||||||
|
salePrice: number;
|
||||||
|
saleStartDate: Date;
|
||||||
|
saleEndDate: Date;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export interface GameEventItem {
|
||||||
|
type: number;
|
||||||
|
id: number;
|
||||||
|
startDate: Date;
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export interface GameMessageItem {
|
||||||
|
type: number;
|
||||||
|
id: number;
|
||||||
|
message: string;
|
||||||
|
startDate: Date;
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface GameRankingItem {
|
||||||
|
id: bigint;
|
||||||
|
point: bigint;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export interface GameSaleItem {
|
||||||
|
orderId: number;
|
||||||
|
type: number;
|
||||||
|
id: number;
|
||||||
|
rate: number;
|
||||||
|
startDate: Date;
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export interface UserActivityItem {
|
||||||
|
kind: number;
|
||||||
|
activityId: number; // This is just called "id" in the JSON!
|
||||||
|
sortNumber: number;
|
||||||
|
param1: number;
|
||||||
|
param2: number;
|
||||||
|
param3: number;
|
||||||
|
param4: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export interface UserCharacterItem {
|
||||||
|
characterId: number;
|
||||||
|
playCount: number;
|
||||||
|
level: number;
|
||||||
|
skillId: number;
|
||||||
|
friendshipExp: number;
|
||||||
|
isValid: boolean;
|
||||||
|
isNewMark: boolean;
|
||||||
|
param1: number;
|
||||||
|
param2: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export interface UserChargeItem {
|
||||||
|
chargeId: number;
|
||||||
|
stock: number;
|
||||||
|
purchaseDate: Date;
|
||||||
|
validDate: Date;
|
||||||
|
param1: number;
|
||||||
|
param2: number;
|
||||||
|
paramDate: Date;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export interface UserCourseItem {
|
||||||
|
courseId: number;
|
||||||
|
classId: number;
|
||||||
|
playCount: number;
|
||||||
|
scoreMax: number;
|
||||||
|
isFullCombo: boolean;
|
||||||
|
isAllJustice: boolean;
|
||||||
|
isSuccess: boolean;
|
||||||
|
scoreRank: number;
|
||||||
|
eventId: number;
|
||||||
|
lastPlayDate: Date;
|
||||||
|
param1: number;
|
||||||
|
param2: number;
|
||||||
|
param3: number;
|
||||||
|
param4: number;
|
||||||
|
isClear: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
export interface UserDataItem {
|
||||||
|
/** NFC LUID */
|
||||||
|
accessCode: string;
|
||||||
|
|
||||||
|
/** Uses wide latin chars */
|
||||||
|
userName: string;
|
||||||
|
|
||||||
|
isWebJoin: boolean;
|
||||||
|
webLimitDate: Date;
|
||||||
|
level: number;
|
||||||
|
reincarnationNum: number;
|
||||||
|
exp: number;
|
||||||
|
point: number;
|
||||||
|
totalPoint: bigint;
|
||||||
|
playCount: number;
|
||||||
|
multiPlayCount: number;
|
||||||
|
multiWinCount: number;
|
||||||
|
requestResCount: number;
|
||||||
|
acceptResCount: number;
|
||||||
|
successResCount: number;
|
||||||
|
playerRating: number;
|
||||||
|
highestRating: number;
|
||||||
|
nameplateId: number;
|
||||||
|
frameId: number;
|
||||||
|
characterId: number;
|
||||||
|
trophyId: number;
|
||||||
|
playedTutorialBit: number;
|
||||||
|
firstTutorialCancelNum: number;
|
||||||
|
masterTutorialCancelNum: number;
|
||||||
|
totalRepertoireCount: number;
|
||||||
|
totalMapNum: number;
|
||||||
|
totalHiScore: bigint;
|
||||||
|
totalBasicHighScore: bigint;
|
||||||
|
totalAdvancedHighScore: bigint;
|
||||||
|
totalExpertHighScore: bigint;
|
||||||
|
totalMasterHighScore: bigint;
|
||||||
|
eventWatchedDate: Date;
|
||||||
|
friendCount: number;
|
||||||
|
isMaimai: boolean;
|
||||||
|
firstGameId: string;
|
||||||
|
firstRomVersion: string;
|
||||||
|
firstDataVersion: string;
|
||||||
|
firstPlayDate: Date;
|
||||||
|
lastGameId: string;
|
||||||
|
lastRomVersion: string;
|
||||||
|
lastDataVersion: string;
|
||||||
|
lastPlayDate: Date;
|
||||||
|
|
||||||
|
/** ALLNet place ID */
|
||||||
|
lastPlaceId: number;
|
||||||
|
|
||||||
|
/** ALLNet place name */
|
||||||
|
lastPlaceName: string;
|
||||||
|
|
||||||
|
/** ALLNet "region0" */
|
||||||
|
lastRegionId: string;
|
||||||
|
|
||||||
|
/** ALLNet "region_name0" */
|
||||||
|
lastRegionName: string;
|
||||||
|
|
||||||
|
/** ALLNet "allnet_id" string */
|
||||||
|
lastAllNetId: string;
|
||||||
|
|
||||||
|
/** Keychip ID */
|
||||||
|
lastClientId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
export interface UserDataExItem {
|
||||||
|
compatibleCmVersion: string;
|
||||||
|
medal: number;
|
||||||
|
mapIconId: number;
|
||||||
|
voiceId: number;
|
||||||
|
ext1: number;
|
||||||
|
ext2: number;
|
||||||
|
ext3: number;
|
||||||
|
ext4: number;
|
||||||
|
ext5: number;
|
||||||
|
ext6: number;
|
||||||
|
ext7: number;
|
||||||
|
ext8: number;
|
||||||
|
ext9: number;
|
||||||
|
ext10: number;
|
||||||
|
ext11: number;
|
||||||
|
ext12: number;
|
||||||
|
ext13: number;
|
||||||
|
ext14: number;
|
||||||
|
ext15: number;
|
||||||
|
ext16: number;
|
||||||
|
ext17: number;
|
||||||
|
ext18: number;
|
||||||
|
ext19: number;
|
||||||
|
ext20: number;
|
||||||
|
extStr1: string;
|
||||||
|
extStr2: string;
|
||||||
|
extStr3: string;
|
||||||
|
extStr4: string;
|
||||||
|
extStr5: string;
|
||||||
|
extLong1: bigint;
|
||||||
|
extLong2: bigint;
|
||||||
|
extLong3: bigint;
|
||||||
|
extLong4: bigint;
|
||||||
|
extLong5: bigint;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export interface UserDuelListItem {
|
||||||
|
duelId: number;
|
||||||
|
progress: number;
|
||||||
|
point: number;
|
||||||
|
isClear: boolean;
|
||||||
|
lastPlayDate: Date;
|
||||||
|
param1: number;
|
||||||
|
param2: number;
|
||||||
|
param3: number;
|
||||||
|
param4: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export interface UserGameOptionItem {
|
||||||
|
bgInfo: number;
|
||||||
|
fieldColor: number;
|
||||||
|
guideSound: number;
|
||||||
|
soundEffect: number;
|
||||||
|
guideLine: number;
|
||||||
|
speed: number;
|
||||||
|
optionSet: number;
|
||||||
|
matching: number;
|
||||||
|
judgePos: number;
|
||||||
|
rating: number;
|
||||||
|
judgeJustice: number;
|
||||||
|
judgeAttack: number;
|
||||||
|
headphone: number;
|
||||||
|
playerLevel: number;
|
||||||
|
successTap: number;
|
||||||
|
successExTap: number;
|
||||||
|
successSlideHold: number;
|
||||||
|
successAir: number;
|
||||||
|
successFlick: number;
|
||||||
|
successSkill: number;
|
||||||
|
successTapTimbre: number;
|
||||||
|
privacy: number;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user