forked from NewEriduPubSec/JaneDoe-ZS
Hi
This commit is contained in:
parent
2fa1067e96
commit
2de8ee290a
131 changed files with 72712 additions and 1 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
target/
|
||||
Cargo.lock
|
||||
|
||||
/nap_proto/nap.proto
|
||||
/nap_proto/bin.server.proto
|
||||
|
||||
/nap_sdk.toml
|
||||
/nap_gameserver.toml
|
76
Cargo.toml
Normal file
76
Cargo.toml
Normal file
|
@ -0,0 +1,76 @@
|
|||
[workspace]
|
||||
members = ["nap_common", "nap_sdk", "nap_proto", "nap_gameserver", "nap_data"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
# Runtime
|
||||
tokio = { version = "1.36.0", features = ["full"] }
|
||||
tokio-util = { version = "0.7.10", features = ["io"] }
|
||||
|
||||
# Serialization
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.114"
|
||||
toml = "0.8.4"
|
||||
rbase64 = "2.0.3"
|
||||
prost = "0.12.3"
|
||||
prost-types = "0.12.3"
|
||||
prost-build = "0.12.3"
|
||||
|
||||
# Cryptography
|
||||
password-hash = { version = "0.5.0", features = ["alloc", "rand_core"] }
|
||||
pbkdf2 = { version = "0.12.2", features = ["simple"] }
|
||||
rand_mt = "4.2.2"
|
||||
rsa = { version = "0.9.6", features = [
|
||||
"sha1",
|
||||
"nightly",
|
||||
"pkcs5",
|
||||
"serde",
|
||||
"sha2",
|
||||
] }
|
||||
|
||||
# Http
|
||||
axum = "0.7.5"
|
||||
|
||||
# Database
|
||||
sqlx = { version = "0.7.4", features = ["postgres", "runtime-tokio-rustls"] }
|
||||
|
||||
# Logging
|
||||
env_logger = "0.11.3"
|
||||
tracing = "0.1.40"
|
||||
tracing-futures = "0.2.5"
|
||||
tracing-log = { version = "0.2.0", features = ["std", "log-tracer"] }
|
||||
tracing-subscriber = { version = "0.3.18", features = [
|
||||
"env-filter",
|
||||
"registry",
|
||||
"std",
|
||||
"tracing",
|
||||
"tracing-log",
|
||||
] }
|
||||
tracing-bunyan-formatter = "0.3.9"
|
||||
|
||||
# Util
|
||||
thiserror = "1.0.61"
|
||||
paste = "1.0.15"
|
||||
hex = "0.4.3"
|
||||
rand = "0.8.5"
|
||||
byteorder = "1.5.0"
|
||||
atomic_enum = "0.3.0"
|
||||
num_enum = "0.7.2"
|
||||
dashmap = "6.0.1"
|
||||
regex = "1.10.5"
|
||||
ansi_term = "0.12.1"
|
||||
|
||||
# Internal
|
||||
common = { path = "nap_common" }
|
||||
data = { path = "nap_data" }
|
||||
proto = { path = "nap_proto" }
|
||||
proto_gen = { path = "nap_proto/proto_gen" }
|
||||
|
||||
[profile.release]
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
lto = true # Link-time optimization.
|
||||
opt-level = 3 # Optimize for speed.
|
||||
codegen-units = 1 # Maximum size reduction optimizations.
|
58
README.md
58
README.md
|
@ -1,3 +1,59 @@
|
|||
# JaneDoe-ZS
|
||||
|
||||
Server emulator for Zenless Zone Zero 1.1.1
|
||||
#### Zenless Zone Zero 1.1.1 server emulator written in Rust.
|
||||
![screenshot](https://git.xeondev.com/NewEriduPubSec/JaneDoe-ZS/raw/branch/master/screenshot.png)
|
||||
|
||||
### Current features
|
||||
- Logging in
|
||||
- Fully playable prologue
|
||||
- Player progress saving with PostgreSQL
|
||||
- Unlock all characters
|
||||
- Training battle
|
||||
|
||||
### Requirements
|
||||
- [Rust](https://www.rust-lang.org/tools/install)
|
||||
- [PostgreSQL](https://www.postgresql.org/download/)
|
||||
|
||||
**NOTE**: Nightly Rust is required to build the project. To install it, first install
|
||||
Rust itself, then run the following command:
|
||||
|
||||
```sh
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
```
|
||||
|
||||
### Setup
|
||||
#### Server
|
||||
##### a) building from sources
|
||||
```
|
||||
git clone https://git.xeondev.com/NewEriduPubSec/JaneDoe-ZS.git
|
||||
cd JaneDoe-ZS
|
||||
cargo run --bin nap-sdk
|
||||
cargo run --bin nap-gameserver
|
||||
```
|
||||
|
||||
##### b) using pre-built binaries
|
||||
Navigate to the [Releases](https://git.xeondev.com/NewEriduPubSec/JaneDoe-ZS/releases)
|
||||
page and download the latest release for your platform.<br>
|
||||
Launch `nap-sdk` and `nap-gameserver`
|
||||
|
||||
#### Database
|
||||
You have to put your PostgreSQL database credentials in both `nap_sdk.toml` and `nap_gameserver.toml` configuration files.
|
||||
```
|
||||
[database]
|
||||
username = "root"
|
||||
password = "root"
|
||||
host = "localhost:5432"
|
||||
name = "nap"
|
||||
```
|
||||
|
||||
### Connecting
|
||||
[Get ZZZ 1.1.1 beta client](https://nogatekeep.ing/assets/nap/pc/napcnbeta_1.1.1.7z),
|
||||
apply [encryption patch](https://git.xeondev.com/NewEriduPubSec/JaneDoe-Patch) and follow its instructions.<br>
|
||||
**NOTE**: You should create a game account. By default, you can do so at http://127.0.0.1:21000/account/register
|
||||
|
||||
### Troubleshooting
|
||||
[Visit our discord](https://discord.xeondev.com/) if you have any questions/issues
|
||||
|
||||
### Support
|
||||
If you want to support this project, feel free to [send a tip via boosty](https://boosty.to/xeondev/donate)
|
||||
|
|
394
assets/FileCfg/AvatarBaseTemplateTb.json
Normal file
394
assets/FileCfg/AvatarBaseTemplateTb.json
Normal file
|
@ -0,0 +1,394 @@
|
|||
[
|
||||
{
|
||||
"ID": 1011,
|
||||
"CodeName": "Avatar_Female_Size02_Anbi_En",
|
||||
"Name": "Avatar_Female_Size02_Anbi",
|
||||
"FullName": "Avatar_Female_Size02_Anbi_FullName",
|
||||
"AudioEventReplaceParam": "anbi",
|
||||
"AudioBank": "BK_Anbi|BK_CHR_Common|BK_Anbi_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 2,
|
||||
"Gender": 2,
|
||||
"Camp": 1,
|
||||
"Unk2": ["1:1:2", "2:203:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1021,
|
||||
"CodeName": "Avatar_Female_Size01_Tsubaki_En",
|
||||
"Name": "Avatar_Female_Size01_Tsubaki",
|
||||
"FullName": "Avatar_Female_Size01_Tsubaki_FullName",
|
||||
"AudioEventReplaceParam": "tsubaki",
|
||||
"AudioBank": "BK_Tsubaki|BK_CHR_Common|BK_Tsubaki_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [200],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 1,
|
||||
"Unk2": ["1:1:2", "2:200:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1031,
|
||||
"CodeName": "Avatar_Female_Size02_Nostradamus_En",
|
||||
"Name": "Avatar_Female_Size02_Nostradamus",
|
||||
"FullName": "Avatar_Female_Size02_Nostradamus_FullName",
|
||||
"AudioEventReplaceParam": "nicole",
|
||||
"AudioBank": "BK_Nicole|BK_CHR_Common|BK_Nicole_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [205],
|
||||
"Unk1": 4,
|
||||
"Gender": 2,
|
||||
"Camp": 1,
|
||||
"Unk2": ["1:1:2", "2:205:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1041,
|
||||
"CodeName": "Avatar_Female_Size02_Longinus_En",
|
||||
"Name": "Avatar_Female_Size02_Longinus",
|
||||
"FullName": "Avatar_Female_Size02_Longinus_FullName",
|
||||
"AudioEventReplaceParam": "longinus",
|
||||
"AudioBank": "BK_Longinus|BK_CHR_Common|BK_Longinus_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [201],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 5,
|
||||
"Unk2": ["1:5:2", "2:201:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1061,
|
||||
"CodeName": "Avatar_Female_Size01_Corin_En",
|
||||
"Name": "Avatar_Female_Size01_Corin",
|
||||
"FullName": "Avatar_Female_Size01_Corin_FullName",
|
||||
"AudioEventReplaceParam": "corin",
|
||||
"AudioBank": "BK_Corin|BK_CHR_Common|BK_Corin_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [200],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 2,
|
||||
"Unk2": ["1:2:2", "2:200:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1071,
|
||||
"CodeName": "Avatar_Female_Size03_Caesar_En",
|
||||
"Name": "Avatar_Female_Size03_Caesar",
|
||||
"FullName": "Avatar_Female_Size03_Caesar_FullName",
|
||||
"AudioEventReplaceParam": "caesar",
|
||||
"AudioBank": "BK_Caesar|BK_CHR_Common|BK_Caesar_VO",
|
||||
"HitTypes": [101, 102],
|
||||
"ElementTypes": [200],
|
||||
"Unk1": 5,
|
||||
"Gender": 2,
|
||||
"Camp": 4,
|
||||
"Unk2": ["1:4:2", "2:200:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1081,
|
||||
"CodeName": "Avatar_Male_Size03_Billy_En",
|
||||
"Name": "Avatar_Male_Size03_Billy",
|
||||
"FullName": "Avatar_Male_Size03_Billy_FullName",
|
||||
"AudioEventReplaceParam": "billy",
|
||||
"AudioBank": "BK_Billy|BK_CHR_Common|BK_Billy_VO",
|
||||
"HitTypes": [103],
|
||||
"ElementTypes": [200],
|
||||
"Unk1": 1,
|
||||
"Gender": 1,
|
||||
"Camp": 1,
|
||||
"Unk2": ["1:1:2", "2:200:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1091,
|
||||
"CodeName": "Avatar_Female_Size02_Unagi_En",
|
||||
"Name": "Avatar_Female_Size02_Unagi",
|
||||
"FullName": "Avatar_Female_Size02_Unagi_FullName",
|
||||
"AudioEventReplaceParam": "unagi",
|
||||
"AudioBank": "BK_Unagi|BK_CHR_Common|BK_Unagi_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [202],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 6,
|
||||
"Unk2": ["1:6:2", "2:202:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1101,
|
||||
"CodeName": "Avatar_Female_Size01_OokumaMari_En",
|
||||
"Name": "Avatar_Female_Size01_OokumaMari",
|
||||
"FullName": "Avatar_Female_Size01_OokumaMari_FullName",
|
||||
"AudioEventReplaceParam": "koleda",
|
||||
"AudioBank": "BK_Koleda|BK_CHR_Common|BK_Koleda_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [201],
|
||||
"Unk1": 2,
|
||||
"Gender": 2,
|
||||
"Camp": 3,
|
||||
"Unk2": ["1:3:2", "2:201:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1111,
|
||||
"CodeName": "Avatar_Male_Size03_Anton_En",
|
||||
"Name": "Avatar_Male_Size03_Anton",
|
||||
"FullName": "Avatar_Male_Size03_Anton_FullName",
|
||||
"AudioEventReplaceParam": "anton",
|
||||
"AudioBank": "BK_Anton|BK_CHR_Common|BK_Anton_VO",
|
||||
"HitTypes": [103],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 1,
|
||||
"Gender": 1,
|
||||
"Camp": 3,
|
||||
"Unk2": ["1:3:2", "2:203:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1121,
|
||||
"CodeName": "Avatar_Male_Size03_Ben_En",
|
||||
"Name": "Avatar_Male_Size03_Ben",
|
||||
"FullName": "Avatar_Male_Size03_Ben_FullName",
|
||||
"AudioEventReplaceParam": "ben",
|
||||
"AudioBank": "BK_Ben|BK_CHR_Common|BK_Ben_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [201],
|
||||
"Unk1": 5,
|
||||
"Gender": 1,
|
||||
"Camp": 3,
|
||||
"Unk2": ["1:3:2", "2:201:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1131,
|
||||
"CodeName": "Avatar_Female_Size01_Aokaku_En",
|
||||
"Name": "Avatar_Female_Size01_Aokaku",
|
||||
"FullName": "Avatar_Female_Size01_Aokaku_FullName",
|
||||
"AudioEventReplaceParam": "aokaku",
|
||||
"AudioBank": "BK_Aokaku|BK_CHR_Common|BK_Aokaku_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [202],
|
||||
"Unk1": 4,
|
||||
"Gender": 2,
|
||||
"Camp": 6,
|
||||
"Unk2": ["1:6:2", "2:202:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1141,
|
||||
"CodeName": "Avatar_Male_Size03_Lycaon_En",
|
||||
"Name": "Avatar_Male_Size03_Lycaon",
|
||||
"FullName": "Avatar_Male_Size03_Lycaon_FullName",
|
||||
"AudioEventReplaceParam": "lycaon",
|
||||
"AudioBank": "BK_Lycaon|BK_CHR_Common|BK_Lycaon_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [202],
|
||||
"Unk1": 2,
|
||||
"Gender": 1,
|
||||
"Camp": 2,
|
||||
"Unk2": ["1:2:2", "2:202:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1151,
|
||||
"CodeName": "Avatar_Female_Size01_Lucy_En",
|
||||
"Name": "Avatar_Female_Size01_Lucy",
|
||||
"FullName": "Avatar_Female_Size01_Lucy_FullName",
|
||||
"AudioEventReplaceParam": "lucy",
|
||||
"AudioBank": "BK_Lucy|BK_CHR_Common|BK_Lucy_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [201],
|
||||
"Unk1": 4,
|
||||
"Gender": 2,
|
||||
"Camp": 4,
|
||||
"Unk2": ["1:4:2", "2:201:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1161,
|
||||
"CodeName": "Avatar_Male_Size02_Lighter_En",
|
||||
"Name": "Avatar_Male_Size02_Lighter",
|
||||
"FullName": "Avatar_Male_Size02_Lighter_FullName",
|
||||
"AudioEventReplaceParam": "lighter",
|
||||
"AudioBank": "BK_Lighter|BK_CHR_Common|BK_Lighter_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [201],
|
||||
"Unk1": 1,
|
||||
"Gender": 1,
|
||||
"Camp": 4,
|
||||
"Unk2": ["1:4:2", "2:201:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1171,
|
||||
"CodeName": "Avatar_Female_Size02_Burnice_En",
|
||||
"Name": "Avatar_Female_Size02_Burnice",
|
||||
"FullName": "Avatar_Female_Size02_Burnice_FullName",
|
||||
"AudioEventReplaceParam": "burnice",
|
||||
"AudioBank": "BK_Burnice|BK_CHR_Common|BK_Burnice_VO",
|
||||
"HitTypes": [103],
|
||||
"ElementTypes": [201],
|
||||
"Unk1": 3,
|
||||
"Gender": 2,
|
||||
"Camp": 4,
|
||||
"Unk2": ["1:4:2", "2:201:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1181,
|
||||
"CodeName": "Avatar_Female_Size03_Lisa_En",
|
||||
"Name": "Avatar_Female_Size03_Lisa",
|
||||
"FullName": "Avatar_Female_Size03_Lisa_FullName",
|
||||
"AudioEventReplaceParam": "lisa",
|
||||
"AudioBank": "BK_Lisa|BK_CHR_Common|BK_Lisa_VO",
|
||||
"HitTypes": [103],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 3,
|
||||
"Gender": 2,
|
||||
"Camp": 3,
|
||||
"Unk2": ["1:3:2", "2:203:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1191,
|
||||
"CodeName": "Avatar_Female_Size02_Ellen_En",
|
||||
"Name": "Avatar_Female_Size02_Ellen",
|
||||
"FullName": "Avatar_Female_Size02_Ellen_FullName",
|
||||
"AudioEventReplaceParam": "ellen",
|
||||
"AudioBank": "BK_Ellen|BK_CHR_Common|BK_Ellen_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [202],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 2,
|
||||
"Unk2": ["1:2:2", "2:202:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1201,
|
||||
"CodeName": "Avatar_Male_Size01_Harumasa_En",
|
||||
"Name": "Avatar_Male_Size01_Harumasa",
|
||||
"FullName": "Avatar_Male_Size01_Harumasa_FullName",
|
||||
"AudioEventReplaceParam": "harumasa",
|
||||
"AudioBank": "BK_Harumasa|BK_CHR_Common|BK_Harumasa_VO",
|
||||
"HitTypes": [103],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 1,
|
||||
"Gender": 1,
|
||||
"Camp": 6,
|
||||
"Unk2": ["1:6:2", "2:200:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1211,
|
||||
"CodeName": "Avatar_Female_Size03_Rina_En",
|
||||
"Name": "Avatar_Female_Size03_Rina",
|
||||
"FullName": "Avatar_Female_Size03_Rina_FullName",
|
||||
"AudioEventReplaceParam": "rina",
|
||||
"AudioBank": "BK_Rina|BK_CHR_Common|BK_Rina_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 4,
|
||||
"Gender": 2,
|
||||
"Camp": 2,
|
||||
"Unk2": ["1:2:2", "2:203:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1221,
|
||||
"CodeName": "Avatar_Female_Size03_Yanagi_En",
|
||||
"Name": "Avatar_Female_Size03_Yanagi",
|
||||
"FullName": "Avatar_Female_Size03_Yanagi_FullName",
|
||||
"AudioEventReplaceParam": "yanagi",
|
||||
"AudioBank": "BK_Yanagi|BK_CHR_Common|BK_Yanagi_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 3,
|
||||
"Gender": 2,
|
||||
"Camp": 6,
|
||||
"Unk2": ["1:6:2", "2:203:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1241,
|
||||
"CodeName": "Avatar_Female_Size03_ZhuYuan_En",
|
||||
"Name": "Avatar_Female_Size03_ZhuYuan",
|
||||
"FullName": "Avatar_Female_Size03_ZhuYuan_FullName",
|
||||
"AudioEventReplaceParam": "ZhuYuan",
|
||||
"AudioBank": "BK_ZhuYuan|BK_CHR_Common|BK_ZhuYuan_VO",
|
||||
"HitTypes": [103],
|
||||
"ElementTypes": [205],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 7,
|
||||
"Unk2": ["1:7:2", "3:4:1"]
|
||||
},
|
||||
{
|
||||
"ID": 1251,
|
||||
"CodeName": "Avatar_Female_Size01_QingYi_En",
|
||||
"Name": "Avatar_Female_Size01_QingYi",
|
||||
"FullName": "Avatar_Female_Size01_QingYi_FullName",
|
||||
"AudioEventReplaceParam": "qingyi",
|
||||
"AudioBank": "BK_QingYi|BK_CHR_Common|BK_QingYi_VO",
|
||||
"HitTypes": [102],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 2,
|
||||
"Gender": 2,
|
||||
"Camp": 7,
|
||||
"Unk2": ["1:7:2", "3:1:1"]
|
||||
},
|
||||
{
|
||||
"ID": 1261,
|
||||
"CodeName": "Avatar_Female_Size03_JaneDoe_En",
|
||||
"Name": "Avatar_Female_Size03_JaneDoe",
|
||||
"FullName": "Avatar_Female_Size03_JaneDoe_FullName",
|
||||
"AudioEventReplaceParam": "janedoe",
|
||||
"AudioBank": "BK_JaneDoe|BK_CHR_Common|BK_JaneDoe_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [200],
|
||||
"Unk1": 3,
|
||||
"Gender": 2,
|
||||
"Camp": 7,
|
||||
"Unk2": ["1:7:2", "3:3:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1271,
|
||||
"CodeName": "Avatar_Male_Size01_Seth_En",
|
||||
"Name": "Avatar_Male_Size01_Seth",
|
||||
"FullName": "Avatar_Male_Size01_Seth_FullName",
|
||||
"AudioEventReplaceParam": "seth",
|
||||
"AudioBank": "BK_Seth|BK_CHR_Common|BK_Seth_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [203],
|
||||
"Unk1": 5,
|
||||
"Gender": 1,
|
||||
"Camp": 7,
|
||||
"Unk2": ["1:7:2", "2:203:2"]
|
||||
},
|
||||
{
|
||||
"ID": 1281,
|
||||
"CodeName": "Avatar_Female_Size01_Clara_En",
|
||||
"Name": "Avatar_Female_Size01_Clara",
|
||||
"FullName": "Avatar_Female_Size01_Clara_FullName",
|
||||
"AudioEventReplaceParam": "clara",
|
||||
"AudioBank": "BK_Clara|BK_CHR_Common|BK_Clara_VO",
|
||||
"HitTypes": [101],
|
||||
"ElementTypes": [200],
|
||||
"Unk1": 3,
|
||||
"Gender": 2,
|
||||
"Camp": 4,
|
||||
"Unk2": ["1:4:2", "2:200:2"]
|
||||
},
|
||||
{
|
||||
"ID": 2011,
|
||||
"CodeName": "Avatar_Male_Size01_Wise_En",
|
||||
"Name": "Avatar_Male_Size01_Wise",
|
||||
"FullName": "Avatar_Male_Size01_Wise_FullName",
|
||||
"AudioEventReplaceParam": "wise",
|
||||
"AudioBank": "BK_Wise",
|
||||
"HitTypes": [0],
|
||||
"ElementTypes": [1],
|
||||
"Unk1": 1,
|
||||
"Gender": 1,
|
||||
"Camp": 0,
|
||||
"Unk2": ["1:0:2", "2:1:2"]
|
||||
},
|
||||
{
|
||||
"ID": 2021,
|
||||
"CodeName": "Avatar_Female_Size02_Belle_En",
|
||||
"Name": "Avatar_Female_Size02_Belle",
|
||||
"FullName": "Avatar_Female_Size02_Belle_FullName",
|
||||
"AudioEventReplaceParam": "belle",
|
||||
"AudioBank": "BK_Belle",
|
||||
"HitTypes": [0],
|
||||
"ElementTypes": [1],
|
||||
"Unk1": 1,
|
||||
"Gender": 2,
|
||||
"Camp": 0,
|
||||
"Unk2": ["1:0:2", "2:1:2"]
|
||||
}
|
||||
]
|
194
assets/FileCfg/PostGirlConfigTemplateTb.json
Normal file
194
assets/FileCfg/PostGirlConfigTemplateTb.json
Normal file
|
@ -0,0 +1,194 @@
|
|||
[
|
||||
{
|
||||
"ID": 3500000,
|
||||
"Name": "Avatar_Male_Size01_Wise",
|
||||
"MEPLHBONBFE": "2011",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "30070001",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole34",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 0
|
||||
},
|
||||
{
|
||||
"ID": 3500001,
|
||||
"Name": "Avatar_Female_Size02_Belle",
|
||||
"MEPLHBONBFE": "2021",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "30070001",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole33",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 0
|
||||
},
|
||||
{
|
||||
"ID": 3510000,
|
||||
"Name": "Avatar_Female_Size02_Anbi",
|
||||
"MEPLHBONBFE": "1011",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211000",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole01",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510001,
|
||||
"Name": "Avatar_Female_Size01_Tsubaki",
|
||||
"MEPLHBONBFE": "1021",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211001",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole11",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510002,
|
||||
"Name": "Avatar_Female_Size02_Nostradamus",
|
||||
"MEPLHBONBFE": "1031",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211002",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole12",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510003,
|
||||
"Name": "Avatar_Male_Size03_Billy",
|
||||
"MEPLHBONBFE": "1081",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211003",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole10",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510004,
|
||||
"Name": "Avatar_Female_Size02_Longinus",
|
||||
"MEPLHBONBFE": "1041",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211004",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole05",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510005,
|
||||
"Name": "Avatar_Female_Size01_OokumaMari",
|
||||
"MEPLHBONBFE": "1101",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211005",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole14",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510006,
|
||||
"Name": "Avatar_Male_Size03_Ben",
|
||||
"MEPLHBONBFE": "1121",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211006",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole16",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510007,
|
||||
"Name": "Avatar_Female_Size03_Lisa",
|
||||
"MEPLHBONBFE": "1181",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211007",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole20",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510008,
|
||||
"Name": "Avatar_Male_Size03_Anton",
|
||||
"MEPLHBONBFE": "1111",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211008",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole15",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510009,
|
||||
"Name": "Avatar_Male_Size03_Lycaon",
|
||||
"MEPLHBONBFE": "1141",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211009",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole18",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510010,
|
||||
"Name": "Avatar_Female_Size02_Ellen",
|
||||
"MEPLHBONBFE": "1191",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211010",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole21",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510011,
|
||||
"Name": "Avatar_Female_Size03_Rina",
|
||||
"MEPLHBONBFE": "1211",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211011",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole22",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510012,
|
||||
"Name": "Avatar_Female_Size01_Corin",
|
||||
"MEPLHBONBFE": "1061",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211012",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole09",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
},
|
||||
{
|
||||
"ID": 3510013,
|
||||
"Name": "Avatar_Female_Size03_ZhuYuan",
|
||||
"MEPLHBONBFE": "1241",
|
||||
"KEGJJDPAKOH": 0,
|
||||
"NOCBKKCNNKA": "1051211013",
|
||||
"LDAILPLNAEG": 0,
|
||||
"ABMDGFGEHGF": "IconRole23",
|
||||
"DGJEECKNEJH": [],
|
||||
"FHNMJNDKHLN": "",
|
||||
"NIENEBHOJNP": 4
|
||||
}
|
||||
]
|
50
assets/FileCfg/ProcedureConfigTemplateTb.json
Normal file
50
assets/FileCfg/ProcedureConfigTemplateTb.json
Normal file
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
{
|
||||
"ProcedureID": 1,
|
||||
"ProcedureType": 2,
|
||||
"ContentID": "5000008",
|
||||
"JumpTos": [2],
|
||||
"ProcedureBanks": [],
|
||||
"ProcedureEvent": ""
|
||||
},
|
||||
{
|
||||
"ProcedureID": 2,
|
||||
"ProcedureType": 4,
|
||||
"ContentID": "CreateRole/LOGIN_P2_mux.mp4",
|
||||
"JumpTos": [3],
|
||||
"ProcedureBanks": ["BK_C00_CS01", "BK_C00_CS01_VO"],
|
||||
"ProcedureEvent": "Play_C00_CS01_BGM"
|
||||
},
|
||||
{
|
||||
"ProcedureID": 3,
|
||||
"ProcedureType": 2,
|
||||
"ContentID": "5000009",
|
||||
"JumpTos": [4],
|
||||
"ProcedureBanks": [],
|
||||
"ProcedureEvent": ""
|
||||
},
|
||||
{
|
||||
"ProcedureID": 4,
|
||||
"ProcedureType": 1,
|
||||
"ContentID": "107010011",
|
||||
"JumpTos": [5],
|
||||
"ProcedureBanks": [],
|
||||
"ProcedureEvent": ""
|
||||
},
|
||||
{
|
||||
"ProcedureID": 5,
|
||||
"ProcedureType": 1,
|
||||
"ContentID": "107010021",
|
||||
"JumpTos": [6],
|
||||
"ProcedureBanks": [],
|
||||
"ProcedureEvent": ""
|
||||
},
|
||||
{
|
||||
"ProcedureID": 6,
|
||||
"ProcedureType": 1,
|
||||
"ContentID": "107010031",
|
||||
"JumpTos": [],
|
||||
"ProcedureBanks": [],
|
||||
"ProcedureEvent": ""
|
||||
}
|
||||
]
|
92
assets/FileCfg/SectionConfigTemplateTb.json
Normal file
92
assets/FileCfg/SectionConfigTemplateTb.json
Normal file
|
@ -0,0 +1,92 @@
|
|||
[
|
||||
{
|
||||
"SectionId": 1,
|
||||
"PhotoName": "Photo_SectionName_01",
|
||||
"Name": "MainCity_Street",
|
||||
"PrimaryEntryName": "Street_PlayerPos_Default",
|
||||
"SecondaryEntryName": "Street_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_Street"
|
||||
},
|
||||
{
|
||||
"SectionId": 2,
|
||||
"PhotoName": "Photo_SectionName_02",
|
||||
"Name": "MainCity_Workshop",
|
||||
"PrimaryEntryName": "Workshop_PlayerPos_Default",
|
||||
"SecondaryEntryName": "Workshop_PlayerPos_Pos2",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_Workshop"
|
||||
},
|
||||
{
|
||||
"SectionId": 3,
|
||||
"PhotoName": "Photo_SectionName_03",
|
||||
"Name": "MainCity_Garage",
|
||||
"PrimaryEntryName": "Garage_PlayerPos_Default",
|
||||
"SecondaryEntryName": "Garage_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_Garage"
|
||||
},
|
||||
{
|
||||
"SectionId": 4,
|
||||
"PhotoName": "Photo_SectionName_04",
|
||||
"Name": "MainCity_ConstructionSite",
|
||||
"PrimaryEntryName": "ConstructionSite_PlayerPos_Default",
|
||||
"SecondaryEntryName": "ConstructionSite_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_ConstructionSite"
|
||||
},
|
||||
{
|
||||
"SectionId": 5,
|
||||
"PhotoName": "Photo_SectionName_05",
|
||||
"Name": "MainCity_SkyScraper",
|
||||
"PrimaryEntryName": "SkyScraper_PlayerPos_Default",
|
||||
"SecondaryEntryName": "SkyScraper_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_SkyScraper"
|
||||
},
|
||||
{
|
||||
"SectionId": 101,
|
||||
"PhotoName": "Photo_SectionName_101",
|
||||
"Name": "MainCity_FortuneSquare",
|
||||
"PrimaryEntryName": "FortuneSquare_PlayerPos_Default",
|
||||
"SecondaryEntryName": "FortuneSquare_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_FortuneSquare"
|
||||
},
|
||||
{
|
||||
"SectionId": 103,
|
||||
"PhotoName": "Photo_SectionName_103",
|
||||
"Name": "MainCity_FortuneHIA",
|
||||
"PrimaryEntryName": "FortuneHIA_PlayerPos_Default",
|
||||
"SecondaryEntryName": "FortuneHIA_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_FortuneHIA"
|
||||
},
|
||||
{
|
||||
"SectionId": 151,
|
||||
"PhotoName": "Photo_SectionName_151",
|
||||
"Name": "Maincity_Zero",
|
||||
"PrimaryEntryName": "Zero_PlayerPos_Default",
|
||||
"SecondaryEntryName": "Zero_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_Zero"
|
||||
},
|
||||
{
|
||||
"SectionId": 153,
|
||||
"PhotoName": "Photo_SectionName_153",
|
||||
"Name": "Maincity_Subway_Street",
|
||||
"PrimaryEntryName": "Subway_PlayerPos_Default",
|
||||
"SecondaryEntryName": "Subway_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_Subway"
|
||||
},
|
||||
{
|
||||
"SectionId": 154,
|
||||
"PhotoName": "Photo_SectionName_154",
|
||||
"Name": "Maincity_Subway_FortuneSquare",
|
||||
"PrimaryEntryName": "SubwayFortuneSquare_PlayerPos_Default",
|
||||
"SecondaryEntryName": "SubwayFortuneSquare_PlayerPos_Default",
|
||||
"ONEGOJKHNJL": 3,
|
||||
"SectionName": "SectionName_Subway"
|
||||
}
|
||||
]
|
317
assets/FileCfg/TrainingQuestTemplateTb.json
Normal file
317
assets/FileCfg/TrainingQuestTemplateTb.json
Normal file
|
@ -0,0 +1,317 @@
|
|||
[
|
||||
{
|
||||
"Id": 12254000,
|
||||
"TrainingType": 1,
|
||||
"BattleEventId": 19800014,
|
||||
"CFFJLDMDEML": "",
|
||||
"IIEMNPJFNJD": "",
|
||||
"MEFHKNFOBCL": 0,
|
||||
"PIIKKAIINOM": 0,
|
||||
"CIPGDEMIEMF": 0,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254001,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19800015,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_1",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSkill_Evade.png",
|
||||
"MEFHKNFOBCL": 122541011,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": -1,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254002,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19800016,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_2",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSkill_ParryAid.png",
|
||||
"MEFHKNFOBCL": 122541011,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": 122541021,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254003,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19800017,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_3",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSkill_ElementAbnormal.png",
|
||||
"MEFHKNFOBCL": 122541011,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": -1,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254004,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810007,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_4",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconStun.png",
|
||||
"MEFHKNFOBCL": 122541011,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": 122541031,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle01.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254005,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810008,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_5",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541081,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541031,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle10.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254006,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810001,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_6",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSupport.png",
|
||||
"MEFHKNFOBCL": 122541031,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": 122541061,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle12.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254007,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810009,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_7",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541021,
|
||||
"PIIKKAIINOM": 122541281,
|
||||
"CIPGDEMIEMF": 122541011,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle11.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254008,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810011,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_8",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconStun.png",
|
||||
"MEFHKNFOBCL": 122541101,
|
||||
"PIIKKAIINOM": 122541121,
|
||||
"CIPGDEMIEMF": 122541111,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle14.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254009,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810002,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_9",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconDefense.png",
|
||||
"MEFHKNFOBCL": 122541121,
|
||||
"PIIKKAIINOM": 122541111,
|
||||
"CIPGDEMIEMF": 122541011,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle16.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254010,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810010,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_10",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAnomaly.png",
|
||||
"MEFHKNFOBCL": 122541181,
|
||||
"PIIKKAIINOM": 122541031,
|
||||
"CIPGDEMIEMF": 122541111,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle20.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254011,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810006,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_11",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541111,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541121,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle15.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254012,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810012,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_12",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconStun.png",
|
||||
"MEFHKNFOBCL": 122541141,
|
||||
"PIIKKAIINOM": 122541061,
|
||||
"CIPGDEMIEMF": 122541031,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle18.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254013,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810003,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_13",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541191,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541131,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle21.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254014,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810013,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_14",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSupport.png",
|
||||
"MEFHKNFOBCL": 122541211,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541111,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle22.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254015,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810014,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_15",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541061,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541081,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle09.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254016,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810015,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_16",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541041,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541121,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle05.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254017,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810004,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_17",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAttack.png",
|
||||
"MEFHKNFOBCL": 122541241,
|
||||
"PIIKKAIINOM": 122541011,
|
||||
"CIPGDEMIEMF": 122541031,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle23.png",
|
||||
"DBIIAEFJHDA": "zhuyuan_release"
|
||||
},
|
||||
{
|
||||
"Id": 12254018,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810005,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_18",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSupport.png",
|
||||
"MEFHKNFOBCL": 122541131,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": 122541061,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle17.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254019,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810016,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_19",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconSupport.png",
|
||||
"MEFHKNFOBCL": 122541151,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": 122541121,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle27.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
},
|
||||
{
|
||||
"Id": 12254021,
|
||||
"TrainingType": 2,
|
||||
"BattleEventId": 19810018,
|
||||
"CFFJLDMDEML": "TrainingRoomTxt_SpecialTraining_Name_21",
|
||||
"IIEMNPJFNJD": "UI/Sprite/A1DynamicLoad/TrainingCourse/UnPacker/TrainingSkill/IconAnomaly.png",
|
||||
"MEFHKNFOBCL": 122541281,
|
||||
"PIIKKAIINOM": 122541081,
|
||||
"CIPGDEMIEMF": 122541151,
|
||||
"LFLIIIIKBHJ": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"OFALKONNAFN": false,
|
||||
"LGGHKLFHOIL": "UI/Sprite/A1DynamicLoad/IconRoleCircle/UnPacker/IconRoleCircle28.png",
|
||||
"DBIIAEFJHDA": ""
|
||||
}
|
||||
]
|
3360
assets/FileCfg/UnlockConfigTemplateTb.json
Normal file
3360
assets/FileCfg/UnlockConfigTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
1446
assets/VideoUSMEncKeys.json
Normal file
1446
assets/VideoUSMEncKeys.json
Normal file
File diff suppressed because it is too large
Load diff
BIN
assets/security/client_secret_key.ec2b
Normal file
BIN
assets/security/client_secret_key.ec2b
Normal file
Binary file not shown.
33
nap_common/Cargo.toml
Normal file
33
nap_common/Cargo.toml
Normal file
|
@ -0,0 +1,33 @@
|
|||
[package]
|
||||
name = "common"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
# Serialization
|
||||
serde.workspace = true
|
||||
toml.workspace = true
|
||||
|
||||
# Cryptography
|
||||
password-hash.workspace = true
|
||||
pbkdf2.workspace = true
|
||||
rsa.workspace = true
|
||||
rand_mt.workspace = true
|
||||
|
||||
# Database
|
||||
sqlx.workspace = true
|
||||
|
||||
# Util
|
||||
thiserror.workspace = true
|
||||
rand.workspace = true
|
||||
byteorder.workspace = true
|
||||
regex.workspace = true
|
||||
ansi_term.workspace = true
|
||||
|
||||
# Logging
|
||||
env_logger.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-futures.workspace = true
|
||||
tracing-log.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing-bunyan-formatter.workspace = true
|
BIN
nap_common/client_public_key.der
Normal file
BIN
nap_common/client_public_key.der
Normal file
Binary file not shown.
26
nap_common/migrations/0001_tables.sql
Normal file
26
nap_common/migrations/0001_tables.sql
Normal file
|
@ -0,0 +1,26 @@
|
|||
CREATE TABLE t_sdk_account (
|
||||
uid int primary key generated always as identity,
|
||||
token varchar(64) NOT NULL,
|
||||
username varchar(40) NOT NULL,
|
||||
password varchar(256) NOT NULL,
|
||||
UNIQUE(username)
|
||||
);
|
||||
|
||||
CREATE TABLE t_combo_token (
|
||||
account_uid varchar(32) primary key,
|
||||
token varchar(64) NOT NULL,
|
||||
device_id varchar(128) NOT NULL,
|
||||
UNIQUE(account_uid, device_id)
|
||||
);
|
||||
|
||||
CREATE TABLE t_user_uid (
|
||||
uid int primary key generated always as identity,
|
||||
account_uid varchar(64) NOT NULL,
|
||||
ext varchar(512) NOT NULL DEFAULT '',
|
||||
UNIQUE(account_uid)
|
||||
);
|
||||
|
||||
CREATE TABLE t_player_data (
|
||||
uid int primary key,
|
||||
bin_data bytea NOT NULL
|
||||
);
|
BIN
nap_common/server_private_key.der
Normal file
BIN
nap_common/server_private_key.der
Normal file
Binary file not shown.
2
nap_common/src/constants.rs
Normal file
2
nap_common/src/constants.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub const SERVER_VERSION: &str = "0.1.0";
|
||||
pub const CLIENT_VERSION: &str = "CNBeta1.1.1";
|
536
nap_common/src/cryptography/ec2b/magic.rs
Normal file
536
nap_common/src/cryptography/ec2b/magic.rs
Normal file
|
@ -0,0 +1,536 @@
|
|||
#![allow(unused)]
|
||||
|
||||
pub const SHIFT_ROWS_TABLE: [u8; 16] = [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11];
|
||||
pub const SHIFT_ROWS_TABLE_INV: [u8; 16] = [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3];
|
||||
pub const LOOKUP_RCON: [u8; 16] = [
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
|
||||
];
|
||||
pub const LOOKUP_SBOX: [u8; 256] = [
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
];
|
||||
pub const LOOKUP_SBOX_INV: [u8; 256] = [
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
];
|
||||
pub const LOOKUP_G2: [u8; 256] = [
|
||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
||||
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
||||
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
|
||||
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
|
||||
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
|
||||
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
|
||||
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
|
||||
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
|
||||
0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
|
||||
0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
|
||||
0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
|
||||
0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
|
||||
0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
|
||||
0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
|
||||
0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
|
||||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5,
|
||||
];
|
||||
pub const LOOKUP_G3: [u8; 256] = [
|
||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
||||
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
||||
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
|
||||
0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
|
||||
0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
|
||||
0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
|
||||
0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
|
||||
0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
|
||||
0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
|
||||
0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
|
||||
0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
|
||||
0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
|
||||
0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
|
||||
0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
|
||||
0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
|
||||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a,
|
||||
];
|
||||
pub const LOOKUP_G9: [u8; 256] = [
|
||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
||||
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
|
||||
0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,
|
||||
0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,
|
||||
0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
|
||||
0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,
|
||||
0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,
|
||||
0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
|
||||
0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,
|
||||
0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,
|
||||
0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
|
||||
0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
|
||||
0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
|
||||
0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
|
||||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46,
|
||||
];
|
||||
pub const LOOKUP_G11: [u8; 256] = [
|
||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
||||
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
||||
0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
|
||||
0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,
|
||||
0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,
|
||||
0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
|
||||
0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,
|
||||
0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,
|
||||
0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
|
||||
0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,
|
||||
0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,
|
||||
0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
|
||||
0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
|
||||
0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
|
||||
0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
|
||||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3,
|
||||
];
|
||||
pub const LOOKUP_G13: [u8; 256] = [
|
||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
||||
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
||||
0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
|
||||
0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,
|
||||
0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,
|
||||
0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
|
||||
0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,
|
||||
0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,
|
||||
0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
|
||||
0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,
|
||||
0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,
|
||||
0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
|
||||
0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
|
||||
0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
|
||||
0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
|
||||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97,
|
||||
];
|
||||
pub const LOOKUP_G14: [u8; 256] = [
|
||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
||||
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
||||
0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
|
||||
0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,
|
||||
0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,
|
||||
0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
|
||||
0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,
|
||||
0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,
|
||||
0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
|
||||
0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,
|
||||
0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,
|
||||
0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
|
||||
0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
|
||||
0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
|
||||
0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
|
||||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d,
|
||||
];
|
||||
pub const KEY_XORPAD_TABLE: [u8; 16] = [
|
||||
0xA2, 0x25, 0x25, 0x99, 0xB7, 0x62, 0xF4, 0x39, 0x28, 0xE1, 0xB7, 0x73, 0x91, 0x05, 0x25, 0x87,
|
||||
];
|
||||
pub const AES_XORPAD_TABLE: [[u8; 2816]; 2] = [
|
||||
[
|
||||
0xDE, 0xAD, 0xCA, 0xFE, 0xFA, 0xCE, 0xB0, 0x0C, 0xDE, 0xAD, 0xCA, 0xFE, 0xFA, 0xCE, 0xB0,
|
||||
0x0C, 0x3A, 0xE6, 0xDE, 0x9C, 0x81, 0xBA, 0x7C, 0xC6, 0x12, 0x1B, 0xAF, 0xD2, 0x8A, 0xBA,
|
||||
0xF5, 0xE6, 0x41, 0xDF, 0x71, 0xBA, 0x37, 0x11, 0x50, 0xF3, 0xF3, 0x62, 0x6E, 0x04, 0xF1,
|
||||
0x14, 0xFC, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x7B, 0x52, 0x7C,
|
||||
0x19, 0x98, 0x35, 0x96, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0,
|
||||
0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6,
|
||||
0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81,
|
||||
0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A,
|
||||
0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A,
|
||||
0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB,
|
||||
0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A,
|
||||
0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1,
|
||||
0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA,
|
||||
0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE,
|
||||
0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0,
|
||||
0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B,
|
||||
0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC,
|
||||
0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71,
|
||||
0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25,
|
||||
0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E,
|
||||
0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76,
|
||||
0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18,
|
||||
0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E,
|
||||
0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69,
|
||||
0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47,
|
||||
0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62,
|
||||
0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8,
|
||||
0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0,
|
||||
0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3,
|
||||
0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E,
|
||||
0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48,
|
||||
0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33,
|
||||
0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78,
|
||||
0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B,
|
||||
0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E,
|
||||
0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71,
|
||||
0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53,
|
||||
0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA,
|
||||
0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18,
|
||||
0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5,
|
||||
0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0,
|
||||
0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82,
|
||||
0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73,
|
||||
0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2,
|
||||
0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE,
|
||||
0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7,
|
||||
0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F,
|
||||
0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C,
|
||||
0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2,
|
||||
0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E,
|
||||
0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF,
|
||||
0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC,
|
||||
0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E,
|
||||
0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00,
|
||||
0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8,
|
||||
0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92,
|
||||
0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35,
|
||||
0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93,
|
||||
0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67,
|
||||
0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C,
|
||||
0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC,
|
||||
0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6,
|
||||
0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2,
|
||||
0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56,
|
||||
0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37,
|
||||
0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A,
|
||||
0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA,
|
||||
0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9,
|
||||
0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0,
|
||||
0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6,
|
||||
0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81,
|
||||
0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A,
|
||||
0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A,
|
||||
0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB,
|
||||
0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A,
|
||||
0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1,
|
||||
0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA,
|
||||
0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE,
|
||||
0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0,
|
||||
0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B,
|
||||
0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC,
|
||||
0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71,
|
||||
0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25,
|
||||
0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E,
|
||||
0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76,
|
||||
0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18,
|
||||
0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E,
|
||||
0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69,
|
||||
0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47,
|
||||
0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62,
|
||||
0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8,
|
||||
0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0,
|
||||
0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3,
|
||||
0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E,
|
||||
0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48,
|
||||
0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33,
|
||||
0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78,
|
||||
0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B,
|
||||
0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E,
|
||||
0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71,
|
||||
0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53,
|
||||
0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA,
|
||||
0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18,
|
||||
0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5,
|
||||
0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0,
|
||||
0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82,
|
||||
0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73,
|
||||
0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2,
|
||||
0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE,
|
||||
0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7,
|
||||
0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F,
|
||||
0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C,
|
||||
0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2,
|
||||
0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E,
|
||||
0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF,
|
||||
0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC,
|
||||
0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E,
|
||||
0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00,
|
||||
0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8,
|
||||
0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92,
|
||||
0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35,
|
||||
0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93,
|
||||
0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67,
|
||||
0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C,
|
||||
0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC,
|
||||
0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6,
|
||||
0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2,
|
||||
0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56,
|
||||
0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37,
|
||||
0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A,
|
||||
0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA,
|
||||
0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9,
|
||||
0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0,
|
||||
0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6,
|
||||
0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81,
|
||||
0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A,
|
||||
0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A,
|
||||
0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB,
|
||||
0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A,
|
||||
0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1,
|
||||
0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA,
|
||||
0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE,
|
||||
0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0,
|
||||
0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B,
|
||||
0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC,
|
||||
0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71,
|
||||
0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25,
|
||||
0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E,
|
||||
0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76,
|
||||
0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18,
|
||||
0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E,
|
||||
0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69,
|
||||
0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47,
|
||||
0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62,
|
||||
0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8,
|
||||
0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0,
|
||||
0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3,
|
||||
0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E,
|
||||
0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48,
|
||||
0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33,
|
||||
0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78,
|
||||
0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B,
|
||||
0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E,
|
||||
0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71,
|
||||
0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53,
|
||||
0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA,
|
||||
0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18,
|
||||
0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5,
|
||||
0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0,
|
||||
0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82,
|
||||
0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73,
|
||||
0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2,
|
||||
0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE,
|
||||
0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7,
|
||||
0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F,
|
||||
0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C,
|
||||
0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2,
|
||||
0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E,
|
||||
0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF,
|
||||
0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC,
|
||||
0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E,
|
||||
0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00,
|
||||
0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8,
|
||||
0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92,
|
||||
0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35,
|
||||
0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93,
|
||||
0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67,
|
||||
0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56,
|
||||
],
|
||||
[
|
||||
0xC3, 0x20, 0x20, 0xB4, 0xAF, 0x0E, 0x82, 0x2E, 0xEF, 0x29, 0xFE, 0x75, 0x1D, 0xDB, 0x4B,
|
||||
0x86, 0x86, 0x23, 0x28, 0x72, 0xA3, 0xF4, 0x1B, 0x4F, 0x5F, 0x0E, 0x02, 0xB1, 0xAC, 0x0D,
|
||||
0xE6, 0x4F, 0x8B, 0x0B, 0x3F, 0xF3, 0x5F, 0xB5, 0x09, 0x7E, 0x3B, 0xE9, 0x93, 0x29, 0x55,
|
||||
0xE1, 0xB4, 0x9B, 0xCC, 0xCE, 0x37, 0xFC, 0xAB, 0x6B, 0xA4, 0x05, 0xE6, 0xC7, 0x45, 0x34,
|
||||
0xC0, 0xFF, 0x7C, 0x24, 0x89, 0x36, 0xBF, 0x17, 0xAB, 0x91, 0xCA, 0x49, 0xF2, 0x74, 0x80,
|
||||
0xB6, 0x90, 0x60, 0xFF, 0xD2, 0xA9, 0xE5, 0xC9, 0x64, 0xBC, 0x38, 0x40, 0x98, 0xB3, 0xBA,
|
||||
0x8F, 0x8B, 0xBA, 0x9D, 0xF3, 0xCF, 0x57, 0xBA, 0xAC, 0x18, 0xE7, 0xD3, 0x03, 0x01, 0x48,
|
||||
0x29, 0x41, 0xF6, 0x2F, 0x89, 0xD4, 0x9F, 0xD7, 0xD3, 0x05, 0x71, 0x63, 0x30, 0x4E, 0xBB,
|
||||
0xF7, 0xB0, 0x99, 0xFF, 0x43, 0xDA, 0x87, 0xCA, 0xA7, 0x48, 0x92, 0x9E, 0x76, 0xA6, 0xEE,
|
||||
0x48, 0x1C, 0x96, 0x28, 0x8E, 0x54, 0x30, 0xD6, 0xA5, 0xD3, 0x22, 0xA2, 0x30, 0xCB, 0x6A,
|
||||
0x85, 0x26, 0x69, 0xE1, 0x7C, 0xEC, 0xDC, 0xD4, 0x89, 0x2A, 0xB8, 0xAE, 0xDF, 0x12, 0x6E,
|
||||
0x39, 0x8A, 0x9B, 0x48, 0x61, 0xF9, 0x4B, 0x34, 0xD0, 0xF1, 0x60, 0x87, 0xBA, 0x88, 0x86,
|
||||
0x68, 0x8C, 0xBE, 0xC1, 0x9C, 0xAE, 0x30, 0xBC, 0xE6, 0x62, 0xFF, 0xEB, 0xBB, 0x88, 0x7C,
|
||||
0xD2, 0xBB, 0x57, 0xB4, 0x02, 0x82, 0x06, 0x72, 0xD2, 0x94, 0x60, 0x86, 0x4A, 0x29, 0xF0,
|
||||
0xEA, 0xD3, 0x88, 0x92, 0xF1, 0x22, 0xD1, 0x5C, 0x88, 0x65, 0xE6, 0xFB, 0xEE, 0x28, 0x79,
|
||||
0x86, 0x68, 0x7D, 0xA6, 0x5A, 0xBF, 0xBD, 0x7D, 0x15, 0xEF, 0x05, 0xF6, 0xF9, 0xE0, 0x11,
|
||||
0xD6, 0x30, 0x94, 0xF2, 0x6C, 0x3D, 0x0A, 0xDB, 0xC5, 0x0E, 0xDC, 0xF2, 0xFD, 0x1F, 0x61,
|
||||
0x91, 0x5D, 0x80, 0x69, 0xA3, 0xDB, 0x35, 0x98, 0x4E, 0x4A, 0xC1, 0x49, 0x76, 0xAB, 0xC0,
|
||||
0x67, 0x36, 0x3F, 0xA4, 0xC6, 0xE8, 0xCA, 0x25, 0x44, 0x63, 0x23, 0xB5, 0xC8, 0xBB, 0x3A,
|
||||
0xAC, 0xA1, 0x09, 0xC3, 0x10, 0x57, 0xA5, 0x5B, 0x3B, 0x33, 0x21, 0xCD, 0x3C, 0x88, 0xAE,
|
||||
0x1E, 0x8F, 0xC1, 0xD6, 0xFB, 0x94, 0x61, 0x38, 0xAB, 0xF1, 0x9C, 0x06, 0xCB, 0x89, 0x58,
|
||||
0x9A, 0xF4, 0xF4, 0x33, 0x80, 0x66, 0x13, 0xC0, 0xFD, 0xE2, 0x16, 0xE0, 0x89, 0x65, 0xE2,
|
||||
0xC1, 0xA6, 0xE3, 0x74, 0xD2, 0x5F, 0xA0, 0x76, 0xAD, 0xF5, 0x6B, 0x4F, 0xE0, 0xF7, 0x52,
|
||||
0xB0, 0xB1, 0x48, 0xDD, 0xEE, 0xB6, 0x01, 0x9A, 0x90, 0x91, 0x18, 0xEC, 0xCB, 0xCB, 0xAD,
|
||||
0x04, 0xB6, 0x73, 0xCF, 0x7F, 0xF3, 0xAC, 0xBE, 0xEC, 0x91, 0x44, 0x56, 0x81, 0xB8, 0x74,
|
||||
0xAE, 0x28, 0x5D, 0xC7, 0x5C, 0xAB, 0x8B, 0x56, 0x21, 0x32, 0x91, 0xB9, 0x9E, 0x70, 0xF6,
|
||||
0x9B, 0xAC, 0x50, 0x0B, 0x2E, 0x4B, 0x8B, 0xA2, 0xA5, 0x24, 0x5B, 0x91, 0xDF, 0x24, 0xA7,
|
||||
0xB0, 0x79, 0xA7, 0x16, 0x54, 0x44, 0x2E, 0xBC, 0x48, 0xCD, 0x87, 0xBA, 0xAF, 0xD4, 0xB9,
|
||||
0x1C, 0x0F, 0xAA, 0xFA, 0x3A, 0x3F, 0x3A, 0x3D, 0x68, 0x5A, 0xAE, 0xAC, 0xBA, 0xBE, 0xA3,
|
||||
0x92, 0x6E, 0x38, 0x8E, 0x33, 0x3E, 0x0A, 0xCC, 0xF6, 0xE3, 0x26, 0x57, 0xEC, 0x8E, 0x63,
|
||||
0x31, 0x27, 0xBA, 0x20, 0x4E, 0x7F, 0x34, 0xE5, 0x19, 0xFE, 0x7F, 0xA6, 0x97, 0x90, 0xD6,
|
||||
0x29, 0x1C, 0x3F, 0x8C, 0x3F, 0x81, 0x62, 0x3D, 0xF5, 0x00, 0xD4, 0xC5, 0xE2, 0xE1, 0x42,
|
||||
0x42, 0x8C, 0x65, 0x8F, 0x5A, 0x66, 0x59, 0xE1, 0xDD, 0xEC, 0xDC, 0x1B, 0x4E, 0x63, 0x82,
|
||||
0xFF, 0x02, 0x9D, 0x53, 0xDE, 0xBD, 0xB4, 0x80, 0xCF, 0x2B, 0xB7, 0xDE, 0x69, 0x5D, 0x1B,
|
||||
0xCA, 0xFB, 0xB3, 0xF9, 0xBE, 0xD0, 0xF5, 0x79, 0x86, 0x2F, 0x0E, 0xB6, 0xA9, 0x87, 0xF4,
|
||||
0x68, 0xC1, 0xBF, 0x4F, 0xB8, 0xA6, 0x2D, 0x03, 0xA9, 0x72, 0x04, 0xCA, 0x37, 0x6D, 0x1B,
|
||||
0x90, 0xDD, 0xBC, 0x52, 0xAE, 0xF3, 0xFF, 0x08, 0xDD, 0x4B, 0x46, 0xD0, 0xCD, 0xB1, 0x8A,
|
||||
0x35, 0x9A, 0x02, 0x64, 0x64, 0x2F, 0x57, 0xA5, 0x7B, 0x9A, 0x0D, 0x2B, 0x55, 0x11, 0x3C,
|
||||
0xC0, 0x35, 0x74, 0x69, 0xD9, 0x7B, 0x43, 0x1D, 0xAC, 0xB2, 0xC2, 0x8A, 0xBE, 0x22, 0x45,
|
||||
0x46, 0x76, 0xA9, 0x8A, 0x49, 0xB2, 0x5F, 0xC0, 0xB8, 0xBC, 0xCD, 0x27, 0xF8, 0x14, 0xB2,
|
||||
0xA9, 0x6D, 0x5A, 0x1F, 0xA4, 0x43, 0x1E, 0x0F, 0xDB, 0xA4, 0x9E, 0x2B, 0xCA, 0xFC, 0x98,
|
||||
0x7F, 0xF1, 0x18, 0x87, 0x5B, 0x11, 0x2D, 0xC5, 0xE4, 0x91, 0x20, 0xA9, 0x6A, 0x2D, 0xAC,
|
||||
0xA8, 0xFA, 0x94, 0x57, 0x7F, 0x30, 0x73, 0x08, 0xE8, 0x49, 0xF0, 0xC8, 0x63, 0xDA, 0x83,
|
||||
0x87, 0x2A, 0xC3, 0x31, 0x1A, 0xFC, 0xB7, 0x57, 0xB2, 0x40, 0x46, 0x09, 0x6D, 0x84, 0xB4,
|
||||
0x66, 0xF1, 0x13, 0x16, 0x3A, 0x3A, 0xFB, 0xC6, 0x6E, 0xB0, 0x71, 0xB8, 0x23, 0x74, 0x22,
|
||||
0x89, 0xFC, 0xBE, 0x34, 0xB3, 0x17, 0xB6, 0xC9, 0x68, 0x53, 0x64, 0x47, 0xAF, 0xCA, 0x1D,
|
||||
0x5F, 0xB4, 0x74, 0xA3, 0x77, 0xB5, 0xFB, 0x77, 0xD9, 0x69, 0x2B, 0x3A, 0xAA, 0xAE, 0xE4,
|
||||
0x03, 0x81, 0x6B, 0x3A, 0x35, 0x9C, 0x45, 0x50, 0x9C, 0x76, 0xCE, 0xE3, 0x7F, 0x64, 0x4B,
|
||||
0x9F, 0x83, 0x7B, 0x72, 0xBC, 0x02, 0x1E, 0x94, 0x99, 0xC1, 0x1C, 0x45, 0x19, 0x1D, 0x56,
|
||||
0x74, 0x73, 0xE7, 0xFC, 0x58, 0x72, 0x2D, 0xE3, 0x50, 0xA4, 0x21, 0xBE, 0x81, 0xDF, 0x80,
|
||||
0xDA, 0x40, 0xDB, 0x79, 0x67, 0x0E, 0x94, 0xA3, 0x05, 0xDD, 0xF7, 0x14, 0x28, 0xD6, 0xC4,
|
||||
0x2B, 0xF3, 0xCF, 0x36, 0x08, 0x84, 0xF3, 0xC8, 0x8C, 0xAD, 0xCE, 0x7F, 0x7C, 0x0F, 0xC6,
|
||||
0xFE, 0x05, 0x54, 0x4B, 0x17, 0xA1, 0x83, 0x65, 0x97, 0x29, 0x01, 0x70, 0xC1, 0x16, 0xAE,
|
||||
0x69, 0xA4, 0x90, 0xB9, 0xBE, 0x17, 0x05, 0x50, 0xF1, 0x65, 0x07, 0x23, 0x76, 0x64, 0x84,
|
||||
0x2D, 0x40, 0x34, 0xFD, 0xDF, 0x62, 0x7E, 0x4C, 0x85, 0xD2, 0x6D, 0x17, 0xE1, 0x41, 0x12,
|
||||
0xC6, 0x3E, 0xD6, 0x14, 0xB8, 0x5F, 0x8F, 0x39, 0x65, 0xC2, 0x62, 0x21, 0x06, 0x5C, 0xC9,
|
||||
0xB8, 0x99, 0xA5, 0x00, 0xE3, 0x9C, 0x73, 0xAB, 0xB9, 0x76, 0x12, 0xD2, 0xFA, 0x7F, 0x7D,
|
||||
0x64, 0x63, 0x9E, 0x26, 0xAA, 0x89, 0x85, 0x3A, 0xC9, 0x94, 0x04, 0x97, 0xEC, 0xFD, 0xC5,
|
||||
0xA3, 0xB1, 0x7D, 0xD6, 0x07, 0x9C, 0x47, 0x30, 0x9C, 0x64, 0x97, 0x0E, 0xC6, 0xFC, 0x0B,
|
||||
0xFF, 0xA7, 0xF9, 0x46, 0x5B, 0x2B, 0xDB, 0x9E, 0x1C, 0x85, 0x3A, 0x75, 0xD6, 0xEB, 0x9B,
|
||||
0x15, 0x36, 0xD7, 0x1A, 0x3D, 0xFC, 0x0B, 0x75, 0x08, 0x5E, 0x32, 0x23, 0xE0, 0xA5, 0xAD,
|
||||
0x0F, 0x45, 0xB3, 0x78, 0x20, 0x22, 0x24, 0x64, 0x0C, 0xCF, 0xD6, 0x3C, 0xA4, 0x48, 0xC7,
|
||||
0xB3, 0x6E, 0x02, 0xE2, 0x0A, 0xAB, 0x92, 0xFC, 0x40, 0x7D, 0xF5, 0x02, 0x61, 0x56, 0xAB,
|
||||
0xC5, 0x68, 0x38, 0xE0, 0x01, 0xF1, 0x94, 0x73, 0xC6, 0xFE, 0xC2, 0x34, 0x67, 0x8E, 0xB1,
|
||||
0x73, 0x72, 0xD4, 0x3B, 0xFD, 0x1F, 0xE2, 0xA8, 0xED, 0x20, 0x14, 0x0A, 0x60, 0x6D, 0xD1,
|
||||
0x85, 0x14, 0x05, 0x54, 0x96, 0xC6, 0x3D, 0xB5, 0x1B, 0x37, 0x56, 0x24, 0xF7, 0x7C, 0x0F,
|
||||
0x55, 0xC6, 0xAA, 0x7E, 0x33, 0x2D, 0xE1, 0x97, 0x74, 0xA8, 0xDC, 0xC5, 0xA1, 0xEC, 0x8C,
|
||||
0xEF, 0x28, 0x3B, 0x49, 0x8B, 0x00, 0xED, 0x8B, 0xD9, 0xE9, 0x65, 0xD5, 0x05, 0x7B, 0x6D,
|
||||
0x20, 0xCA, 0x8F, 0x93, 0xB4, 0xCA, 0x36, 0x34, 0x8E, 0x16, 0x46, 0xCE, 0x02, 0x23, 0x43,
|
||||
0x22, 0xF6, 0xBD, 0x10, 0xCC, 0xD0, 0xA3, 0xB0, 0x42, 0xA5, 0xAF, 0x59, 0x72, 0x97, 0x0B,
|
||||
0xAE, 0x80, 0x8D, 0x19, 0xD0, 0x1D, 0x7D, 0x30, 0x4E, 0x5B, 0x46, 0xC0, 0xC2, 0x5C, 0x40,
|
||||
0xFC, 0xF3, 0xEF, 0x05, 0x84, 0xE8, 0x0C, 0x80, 0xD7, 0x37, 0xA1, 0x6F, 0xC1, 0x8C, 0xE0,
|
||||
0xBA, 0xA1, 0x88, 0x7B, 0xE7, 0x20, 0xBF, 0x18, 0x02, 0x40, 0x9F, 0x6F, 0x23, 0x11, 0x78,
|
||||
0x07, 0xD0, 0x92, 0x87, 0x2D, 0xB5, 0xE0, 0xE9, 0xE9, 0xAA, 0x32, 0x88, 0x57, 0xF8, 0x9B,
|
||||
0x01, 0x93, 0x2D, 0x07, 0x77, 0x68, 0x86, 0xAD, 0x06, 0xDE, 0x57, 0xA9, 0xA4, 0x96, 0x33,
|
||||
0x42, 0xF8, 0xFB, 0x23, 0x1F, 0x99, 0xB6, 0x62, 0x93, 0x6B, 0x12, 0xBE, 0x72, 0x9F, 0x96,
|
||||
0x1A, 0xDA, 0x05, 0x60, 0xF1, 0xD5, 0x40, 0x9F, 0x75, 0xF3, 0x1D, 0xBE, 0xD7, 0x87, 0x5D,
|
||||
0x3A, 0x55, 0xF0, 0x9B, 0xBF, 0xE8, 0xB9, 0x72, 0xC2, 0xDD, 0x4D, 0x27, 0xF6, 0xA9, 0x37,
|
||||
0x96, 0x7E, 0x6E, 0x6E, 0x64, 0x37, 0x4E, 0x2E, 0x3F, 0xFD, 0x3C, 0xF4, 0xA6, 0xF5, 0x22,
|
||||
0xA8, 0x43, 0xF4, 0x13, 0x21, 0xB5, 0x4E, 0xA8, 0x6D, 0x50, 0x0A, 0xB3, 0xFE, 0x9F, 0x5C,
|
||||
0xE7, 0x1A, 0xCF, 0x36, 0x42, 0x30, 0x1C, 0x88, 0x7F, 0x29, 0xE9, 0xCD, 0x96, 0xF2, 0x6A,
|
||||
0x52, 0xB2, 0x25, 0x87, 0x63, 0xDC, 0xFC, 0x72, 0xE4, 0xF8, 0x5E, 0xB1, 0x97, 0xB4, 0x1E,
|
||||
0x08, 0x90, 0x68, 0x10, 0x73, 0x7F, 0x94, 0x61, 0x48, 0x49, 0x36, 0x9B, 0x7D, 0xBD, 0xDF,
|
||||
0xCD, 0xB1, 0xA3, 0x7D, 0xFB, 0xDD, 0x97, 0x8A, 0x0D, 0xFC, 0x9A, 0xB8, 0xA9, 0x33, 0xB5,
|
||||
0x4E, 0x50, 0x3D, 0x60, 0x90, 0xEB, 0xAB, 0xB8, 0xCB, 0x6E, 0x32, 0xE4, 0x6B, 0xB0, 0x3F,
|
||||
0x57, 0xB8, 0xA4, 0x6A, 0x7C, 0x00, 0x66, 0x39, 0xB1, 0x22, 0xE2, 0x04, 0x26, 0xA1, 0x5A,
|
||||
0x17, 0xAA, 0x80, 0xB6, 0xC0, 0xF6, 0xCF, 0x7A, 0xF8, 0x60, 0xE9, 0x52, 0xB8, 0x0E, 0x08,
|
||||
0xC0, 0xD5, 0x1F, 0xAB, 0x61, 0x62, 0x1A, 0x83, 0xD1, 0x92, 0xE1, 0x4D, 0x6D, 0xDF, 0x27,
|
||||
0x0E, 0xFF, 0xF9, 0xA3, 0x36, 0xFF, 0x73, 0xEF, 0x1D, 0xAB, 0xAC, 0xBF, 0xA7, 0xB3, 0x29,
|
||||
0xD2, 0xB2, 0x37, 0xAB, 0x08, 0x7D, 0xB6, 0x7E, 0x0D, 0x25, 0xAA, 0x49, 0x29, 0x9F, 0x61,
|
||||
0x52, 0x44, 0x19, 0x1C, 0x51, 0x95, 0x74, 0xB9, 0x3D, 0xDD, 0x95, 0x2C, 0x4F, 0x30, 0x56,
|
||||
0xC9, 0xEF, 0x3D, 0x87, 0x90, 0x1E, 0xF8, 0x69, 0xFF, 0x37, 0x06, 0x27, 0xDB, 0x72, 0x82,
|
||||
0x2C, 0xDE, 0xB8, 0x39, 0x0B, 0x78, 0xB1, 0x1F, 0x37, 0x54, 0xBF, 0x21, 0x32, 0x87, 0xB4,
|
||||
0xD9, 0x49, 0x2D, 0x29, 0x19, 0x43, 0x01, 0xD4, 0xC0, 0xA3, 0xFF, 0x09, 0x6F, 0x69, 0xC8,
|
||||
0x5D, 0x35, 0x1D, 0x10, 0x09, 0x91, 0xB6, 0x12, 0xEC, 0x04, 0xA6, 0x61, 0xEF, 0x73, 0xC7,
|
||||
0x4C, 0x04, 0x8E, 0x3E, 0xAE, 0xD7, 0xC2, 0x84, 0x48, 0xAB, 0x99, 0x96, 0x75, 0xD8, 0xAD,
|
||||
0xA7, 0x5B, 0xDE, 0x72, 0x44, 0x96, 0xC5, 0xB3, 0xEB, 0x8E, 0xED, 0xD6, 0x69, 0x81, 0xE6,
|
||||
0x07, 0x3A, 0x15, 0x0D, 0x66, 0x5F, 0x36, 0xA9, 0xAB, 0x53, 0x82, 0x47, 0x98, 0x27, 0xF2,
|
||||
0x16, 0x95, 0x05, 0x0B, 0xAE, 0xF1, 0x04, 0x92, 0x80, 0x20, 0xA4, 0x9B, 0x43, 0x66, 0x70,
|
||||
0x7F, 0x45, 0x0B, 0x4B, 0x85, 0x95, 0x10, 0x09, 0xC8, 0xD9, 0xF9, 0x5D, 0x40, 0x6D, 0x07,
|
||||
0x69, 0x18, 0xF3, 0xD6, 0x98, 0x61, 0x25, 0x8E, 0xA1, 0xE2, 0x24, 0xBD, 0xF0, 0xFA, 0x89,
|
||||
0xD8, 0x68, 0xB2, 0x03, 0x81, 0x63, 0xF9, 0x42, 0xD4, 0x1A, 0xD9, 0x4D, 0xCD, 0x30, 0x36,
|
||||
0x2D, 0xB1, 0x63, 0xFC, 0xA3, 0x2B, 0xA7, 0x07, 0x50, 0xBC, 0x67, 0xAB, 0x7D, 0x33, 0x1D,
|
||||
0xEC, 0x62, 0xFE, 0xD2, 0x65, 0xAA, 0xBA, 0x37, 0xC9, 0x7F, 0x67, 0x26, 0x9D, 0x8A, 0x8B,
|
||||
0x63, 0x0B, 0xE0, 0x30, 0x65, 0x07, 0x8C, 0xF3, 0xD1, 0xCF, 0x0D, 0xB4, 0x1E, 0xF3, 0x29,
|
||||
0xBE, 0x43, 0x1F, 0x34, 0x1E, 0x52, 0x02, 0xA7, 0x8D, 0x30, 0x2E, 0x3E, 0x39, 0x00, 0xB6,
|
||||
0x7B, 0x5C, 0x29, 0x39, 0xC0, 0x0D, 0xAB, 0xA0, 0x6D, 0x77, 0x3C, 0xB2, 0x18, 0x42, 0x57,
|
||||
0x63, 0xDA, 0x9E, 0xF5, 0xE0, 0x42, 0x43, 0xF6, 0x50, 0xFD, 0x71, 0x9B, 0x30, 0xE0, 0x92,
|
||||
0x8B, 0xD1, 0xE1, 0xC4, 0x96, 0xC9, 0xF5, 0x14, 0xB6, 0xF7, 0xA5, 0x10, 0x77, 0xF4, 0xF9,
|
||||
0xAC, 0xDC, 0x45, 0xE1, 0x3C, 0xD6, 0x0B, 0xA5, 0xE2, 0x58, 0x01, 0x19, 0x39, 0x14, 0x68,
|
||||
0x96, 0xC0, 0xCE, 0xA9, 0xDE, 0x84, 0x22, 0x59, 0x87, 0x70, 0xFD, 0x8A, 0x71, 0x64, 0x79,
|
||||
0x16, 0x37, 0x80, 0x83, 0xFD, 0x9C, 0x73, 0xE6, 0x9C, 0x8B, 0xCD, 0xC0, 0x69, 0x66, 0x90,
|
||||
0x45, 0x0A, 0xC9, 0x81, 0x4A, 0xDA, 0x26, 0xDA, 0xA1, 0x70, 0x03, 0x6C, 0x36, 0x9D, 0xAD,
|
||||
0xD7, 0xE2, 0x1F, 0x27, 0xBE, 0xBB, 0xEC, 0x63, 0xD9, 0xC2, 0x2A, 0x56, 0x4D, 0x63, 0xCD,
|
||||
0x92, 0xEE, 0xAF, 0xCA, 0xD0, 0x11, 0x35, 0x2F, 0x1D, 0xF1, 0x96, 0xD1, 0xAA, 0xDC, 0xF6,
|
||||
0x14, 0x3F, 0xA0, 0xEE, 0x90, 0x83, 0x9F, 0x42, 0x40, 0xE6, 0x2C, 0x10, 0x23, 0x00, 0x23,
|
||||
0x18, 0x8C, 0xA1, 0x26, 0x4B, 0x22, 0xE1, 0x36, 0x07, 0x55, 0xCB, 0xC3, 0xD2, 0xDD, 0x12,
|
||||
0x58, 0x19, 0x75, 0x03, 0xC6, 0xD8, 0x2E, 0xCE, 0x87, 0x1C, 0xC3, 0x15, 0x44, 0x2A, 0x30,
|
||||
0x00, 0x52, 0x39, 0x31, 0x13, 0xF4, 0x25, 0x75, 0x74, 0x15, 0x6C, 0xC5, 0xC1, 0xD2, 0x33,
|
||||
0x75, 0xC2, 0x41, 0x22, 0x28, 0x95, 0xDF, 0x97, 0x6C, 0x31, 0xF8, 0x35, 0xA6, 0x54, 0x29,
|
||||
0x5C, 0xF4, 0x20, 0x97, 0x69, 0xE5, 0x46, 0xFF, 0x34, 0x24, 0x73, 0x12, 0xB8, 0x61, 0x25,
|
||||
0x46, 0xB3, 0x8F, 0xBA, 0x3C, 0xFA, 0x06, 0xFF, 0x3F, 0x66, 0x9D, 0x22, 0x55, 0x46, 0x2F,
|
||||
0xFF, 0x44, 0xDB, 0x25, 0x29, 0xE0, 0x16, 0x6E, 0xEC, 0x87, 0x97, 0x92, 0x37, 0x23, 0x0E,
|
||||
0x52, 0x4E, 0xBB, 0x10, 0xBB, 0x1C, 0x73, 0x75, 0xD1, 0x31, 0xC3, 0xAD, 0xFE, 0xB8, 0x12,
|
||||
0x50, 0xA0, 0x69, 0x91, 0x36, 0xEA, 0x5F, 0x0D, 0xEC, 0x1A, 0x23, 0x4A, 0x7D, 0x94, 0x84,
|
||||
0xC8, 0x4A, 0x58, 0x6A, 0xA1, 0xA3, 0x75, 0xCA, 0x85, 0xE7, 0x96, 0x91, 0x07, 0x05, 0x3A,
|
||||
0x57, 0x61, 0x6A, 0x6F, 0xF1, 0xEF, 0xF7, 0xB3, 0xB1, 0x09, 0xB8, 0x91, 0xA8, 0xF9, 0x57,
|
||||
0xB8, 0x63, 0x95, 0xFF, 0xB4, 0x1C, 0x96, 0xE7, 0xE5, 0xEC, 0x06, 0x3A, 0x11, 0xE6, 0x81,
|
||||
0xAB, 0x23, 0xE4, 0x5E, 0x5A, 0xB6, 0x6B, 0x69, 0x62, 0x6F, 0x9D, 0xC4, 0x08, 0x6F, 0xA6,
|
||||
0xBE, 0x4D, 0x09, 0x12, 0x77, 0xCA, 0xDD, 0xB5, 0x2D, 0x66, 0xCB, 0x4F, 0x4F, 0x11, 0xF2,
|
||||
0x3A, 0x1A, 0x97, 0x1F, 0xFE, 0x50, 0x2F, 0x19, 0x32, 0x05, 0x45, 0xA0, 0x50, 0x60, 0x58,
|
||||
0x40, 0x40, 0x3D, 0xF6, 0xC3, 0x6F, 0x07, 0xC8, 0x26, 0x26, 0x0E, 0x42, 0x22, 0x96, 0x6D,
|
||||
0xFE, 0x95, 0x53, 0x70, 0xDC, 0x92, 0x12, 0x63, 0xFD, 0xA3, 0x7D, 0x6E, 0x44, 0xCD, 0x11,
|
||||
0x2C, 0x51, 0x6F, 0xBC, 0x50, 0xFC, 0x1C, 0xC8, 0x3A, 0x28, 0xF5, 0x39, 0xF8, 0x8C, 0x60,
|
||||
0x5D, 0xA5, 0x4A, 0xFA, 0xAB, 0x04, 0x7F, 0x34, 0x91, 0x53, 0xE7, 0x6C, 0x56, 0xC6, 0x14,
|
||||
0xE4, 0xCC, 0xE4, 0xBB, 0x6E, 0x47, 0x7A, 0x46, 0x6B, 0xE2, 0x88, 0xA0, 0xBD, 0xBD, 0xCC,
|
||||
0x51, 0xF3, 0x37, 0x4B, 0xB3, 0xA0, 0x19, 0x92, 0x48, 0x35, 0xBB, 0xBC, 0x79, 0x78, 0xFF,
|
||||
0x49, 0xC1, 0x2B, 0x93, 0xDF, 0x75, 0xA7, 0xFB, 0x94, 0x89, 0xAF, 0x50, 0x5E, 0x2D, 0xE1,
|
||||
0x78, 0x60, 0x0C, 0xDF, 0xF8, 0x7C, 0xFD, 0xCD, 0x2D, 0xE2, 0xFF, 0xD3, 0xA3, 0x4A, 0x48,
|
||||
0x0D, 0x40, 0x8F, 0x03, 0x4F, 0x2C, 0xBD, 0xFA, 0x2E, 0x16, 0xC3, 0xD4, 0xFD, 0x0B, 0xB3,
|
||||
0xBD, 0x4F, 0x30, 0xAD, 0xD0, 0xAE, 0xCA, 0x77, 0x9D, 0xDD, 0x3D, 0xA3, 0x66, 0xD0, 0xC1,
|
||||
0x6D, 0xCC, 0x3B, 0x56, 0x81, 0x5D, 0x80, 0x07, 0xD8, 0x84, 0x46, 0x71, 0x40, 0x57, 0xB3,
|
||||
0x44, 0x85, 0x63, 0x4E, 0x17, 0x2C, 0xB0, 0x21, 0x98, 0x43, 0x42, 0x04, 0x18, 0x84, 0xFA,
|
||||
0xB1, 0xD7, 0xC5, 0x5C, 0xCA, 0x25, 0x8B, 0x1A, 0x7A, 0x50, 0x60, 0x68, 0x4A, 0x30, 0xEA,
|
||||
0xE6, 0xDE, 0x19, 0xBB, 0x9F, 0x47, 0xEF, 0xDB, 0xC5, 0x81, 0x72, 0xF0, 0x8D, 0xBA, 0x74,
|
||||
0x3A, 0xD1, 0xD5, 0xC6, 0xD1, 0xE0, 0xAE, 0x28, 0x2A, 0x65, 0xE5, 0x0B, 0x09, 0xFA, 0xEA,
|
||||
0x5B, 0xA6, 0xDB, 0x38, 0xD8, 0x67, 0xC0, 0xBE, 0xA1, 0x12, 0x1C, 0x03, 0xB1, 0x81, 0xB8,
|
||||
0x95, 0xDD, 0x78, 0xF8, 0x16, 0x6E, 0xAB, 0xBB, 0xAA, 0x33, 0x54, 0x0E, 0x39, 0x83, 0x24,
|
||||
0x17, 0xB3, 0x0B, 0x3C, 0xA1, 0x62, 0x21, 0xB2, 0xA0, 0xF8, 0x49, 0xAB, 0x8B, 0x80, 0xC6,
|
||||
0x3D, 0xF1, 0x2E, 0x18, 0x44, 0x74, 0x5F, 0x98, 0x92, 0x33, 0xFB, 0xB2, 0x52, 0x6B, 0x97,
|
||||
0xE9, 0x48, 0x12, 0x91, 0x32, 0x50, 0x21, 0x75, 0x74, 0x69, 0x88, 0x54, 0xC6, 0xF3, 0xC9,
|
||||
0x37, 0x3C, 0xB3, 0x89, 0xAB, 0x33, 0x1F, 0x79, 0x57, 0xF7, 0xE4, 0xB5, 0x87, 0x0C, 0xA4,
|
||||
0x99, 0x48, 0x89, 0x63, 0x5F, 0x72, 0xA1, 0xBC, 0xFF, 0xFE, 0xF8, 0xB3, 0xF1, 0x00, 0xE4,
|
||||
0xD4, 0x01, 0x9B, 0xB7, 0x2E, 0x4F, 0xA0, 0x90, 0xE4, 0x9B, 0x6A, 0xA8, 0xBA, 0xE1, 0xD3,
|
||||
0xD5, 0xBC, 0xEB, 0xC5, 0xB2, 0x89, 0xB4, 0xE9, 0x4D, 0x3F, 0x4C, 0xFA, 0x8C, 0xCB, 0xCD,
|
||||
0x22, 0x08, 0xB8, 0xC7, 0xB3, 0xA3, 0xED, 0x6B, 0xAC, 0xF3, 0x2D, 0x98, 0x70, 0x41, 0x47,
|
||||
0x85, 0xE8, 0x6E, 0x31, 0x0A, 0xC2, 0x3E, 0x51, 0x39, 0x55, 0xF8, 0x4A, 0xE9, 0x48, 0x64,
|
||||
0x01, 0xDB, 0x8D, 0xE3, 0xAF, 0xA4, 0xB9, 0xD8, 0x19, 0xCA, 0x86, 0xCA, 0xA1, 0x6C, 0x1C,
|
||||
0x12, 0x3D, 0xA1, 0x02, 0x23, 0x1D, 0x29, 0x5D, 0x94, 0x04, 0xC6, 0x51, 0x01, 0x40, 0x0B,
|
||||
0xB3, 0x69, 0x25, 0x45, 0xEF, 0x43, 0x81, 0x4F, 0x97, 0x57, 0x0D, 0xA1, 0xA5, 0xC9, 0x9D,
|
||||
0xE6, 0x56, 0xB9, 0x38, 0x93, 0xA1, 0x78, 0xC5, 0xBF, 0x75, 0xFE, 0x81, 0x6A, 0x35, 0x64,
|
||||
0x89, 0x64, 0x43, 0x75, 0xFD, 0x29, 0x63, 0xD1, 0x15, 0xAB, 0x43, 0x60, 0x65, 0xDC, 0x98,
|
||||
0xD5, 0xC7, 0x6E, 0xF9, 0xB2, 0x38, 0xFB, 0x6E, 0xB0, 0x34, 0x9C, 0xA3, 0x73, 0x61, 0xF5,
|
||||
0x51, 0xFF, 0x1F, 0xCE, 0xB0, 0x08, 0x83, 0x29, 0xB3, 0x82, 0x07, 0xFA, 0xC4, 0xE5, 0x21,
|
||||
0xD3, 0xA0, 0xD4, 0xC0, 0xF8, 0x1A, 0x65, 0x9B, 0x35, 0x7A, 0xE3, 0x32, 0xA5, 0x4D, 0x77,
|
||||
0x1F, 0x23, 0x19, 0xCC, 0xE1, 0xB3, 0x50, 0x0D, 0xE8, 0x2F, 0x8B, 0x18, 0x89, 0x61, 0xCB,
|
||||
0x22, 0xBA, 0xE0, 0x4A, 0xA2, 0x7F, 0xA5, 0x1B, 0x45, 0x59, 0x33, 0xC4, 0x73, 0xDF, 0x42,
|
||||
0xC6, 0x00, 0x11, 0x37, 0xF2, 0x3C, 0x1B, 0xF4, 0x26, 0xD1, 0x6D, 0x93, 0xC1, 0x94, 0xD2,
|
||||
0x60, 0xE5, 0xF3, 0x91, 0x66, 0x92, 0x3C, 0x65, 0x27, 0xC1, 0x83, 0x13, 0x76, 0x5A, 0x88,
|
||||
0xEC, 0xB2, 0x59, 0x95, 0x18, 0x81, 0x2E, 0x94, 0x96, 0x53, 0x17, 0xB6, 0xFD, 0x8C, 0xCC,
|
||||
0xBE, 0x8D, 0x36, 0xB3, 0xC8, 0xF2, 0xB2, 0xBE, 0x0F, 0x12, 0x99, 0xFF, 0xFA, 0xF9, 0x18,
|
||||
0xAB, 0x30, 0xFA, 0xB1, 0x5B, 0xF2, 0xEE, 0xCA, 0x6E, 0xA1, 0xD9, 0xCE, 0xCC, 0x60, 0xA0,
|
||||
0x4D, 0xFD, 0x7C, 0xAD, 0x4D, 0x50, 0xB6, 0x88, 0x0D, 0x88, 0x3B, 0x28, 0x7F, 0xA1, 0x28,
|
||||
0x41, 0x0A, 0x43, 0xAD, 0xCC, 0x08, 0x14, 0xF3, 0xF2, 0x43, 0xE7, 0xCF, 0x6A, 0x5C, 0x11,
|
||||
0xD0, 0x6D, 0x99, 0xC8, 0x4F, 0xB1, 0x14, 0x06, 0xBC, 0x68, 0x6D, 0xBE, 0xCD, 0xD7, 0x58,
|
||||
0xA2, 0x17, 0xF5, 0x9E, 0xFD, 0xDA, 0xFA, 0xBF, 0x73, 0x57, 0x4A, 0xF8, 0xF3, 0xA9, 0x94,
|
||||
0xB3, 0x01, 0xE9, 0xA3, 0xDA, 0xEA, 0xC1, 0x40, 0x33, 0xAA, 0x3F, 0xE6, 0x0D, 0x6A, 0xE2,
|
||||
0xF3, 0x74, 0xE8, 0x1B, 0x3C, 0x2B, 0x25, 0x44, 0x8E, 0x1C, 0x36, 0xBE, 0xA9, 0x27, 0x6E,
|
||||
0x6A, 0x48, 0x8E, 0x2F, 0x2C, 0x9D, 0x71, 0x66, 0x23, 0x7C, 0x7A, 0x74, 0x93, 0x46, 0x2D,
|
||||
0xCA, 0x6B, 0xC6, 0x33, 0xDA, 0x1E, 0x1E, 0x44, 0x07, 0xFD, 0x89, 0x5D, 0x30, 0x02, 0x4C,
|
||||
0xB1, 0x73, 0xC0, 0x91, 0xEB, 0xA5, 0x61, 0x89, 0xA4, 0x04, 0xFD, 0xD5, 0x5F, 0x54, 0x59,
|
||||
0x81, 0xC3, 0x2A, 0x13, 0x89, 0xDA, 0x68, 0xB6, 0x3A, 0x9C, 0x70, 0x6F, 0x48, 0xB4, 0x3C,
|
||||
0xF8, 0x9B, 0xF8, 0xF2, 0x59, 0xBF, 0xF4, 0x8D, 0x06, 0x58, 0xEA, 0xA2, 0xA6, 0xB4, 0x70,
|
||||
0x08, 0x80, 0x2B, 0x50, 0x13, 0x36, 0x79, 0x17, 0x0B, 0x94, 0x0E, 0x4D, 0xF5, 0xC8, 0x14,
|
||||
0xB9, 0x02, 0x7D, 0xEE, 0x6B, 0xBD, 0x10, 0xB4, 0x85, 0x74, 0xA1, 0xB9, 0x84, 0x67, 0xC6,
|
||||
0x2C, 0xDB, 0xDA, 0x55, 0x54, 0x16, 0xDA, 0x02, 0xB6, 0xDA, 0x2A, 0x9B, 0x51, 0xD6, 0xDC,
|
||||
0x87, 0x80, 0xC1, 0xB8, 0x6F, 0x0C, 0xEF, 0x4B, 0xD1, 0x1A, 0x9F, 0x36, 0x2E, 0x9C, 0x7E,
|
||||
0x5F, 0x17, 0xE2, 0xC1, 0x82, 0x0C, 0x42, 0x0D, 0x15, 0x18, 0xCA,
|
||||
],
|
||||
];
|
175
nap_common/src/cryptography/ec2b/mhy_aes.rs
Normal file
175
nap_common/src/cryptography/ec2b/mhy_aes.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
#![allow(unused)]
|
||||
|
||||
use super::magic::{LOOKUP_G11, LOOKUP_G13, LOOKUP_G14, LOOKUP_G2, LOOKUP_G3, LOOKUP_G9, LOOKUP_RCON, LOOKUP_SBOX, LOOKUP_SBOX_INV, SHIFT_ROWS_TABLE, SHIFT_ROWS_TABLE_INV};
|
||||
|
||||
fn xorr(a: &mut [u8], b: &[u8], n: usize) {
|
||||
(0..n).for_each(|i| a[i] ^= b[i]);
|
||||
}
|
||||
|
||||
fn xor_round_key(state: &mut [u8], keys: &[u8], round: usize) {
|
||||
xorr(state, &keys[round * 16..], 16);
|
||||
}
|
||||
|
||||
fn sub_bytes(a: &mut [u8], n: usize) {
|
||||
(0..n).for_each(|i| a[i] = LOOKUP_SBOX[a[i] as usize]);
|
||||
}
|
||||
|
||||
fn sub_bytes_inv(a: &mut [u8], n: usize) {
|
||||
(0..n).for_each(|i| a[i] = LOOKUP_SBOX_INV[a[i] as usize]);
|
||||
}
|
||||
|
||||
fn key_schedule_core(a: &mut [u8], i: usize) {
|
||||
let temp = a[0];
|
||||
a[0] = a[1];
|
||||
a[1] = a[2];
|
||||
a[2] = a[3];
|
||||
a[3] = temp;
|
||||
sub_bytes(a, 4);
|
||||
a[0] ^= LOOKUP_RCON[i];
|
||||
}
|
||||
|
||||
fn oqs_aes128_load_schedule_c(key: &[u8]) -> [u8; 176] {
|
||||
let mut schedule = [0u8; 176];
|
||||
|
||||
let mut bytes = 16;
|
||||
let mut i = 1;
|
||||
let mut t = [0u8; 4];
|
||||
|
||||
schedule[0..16].copy_from_slice(key);
|
||||
|
||||
while bytes < 176 {
|
||||
t.copy_from_slice(&schedule[bytes - 4..]);
|
||||
key_schedule_core(&mut t, i);
|
||||
i += 1;
|
||||
xorr(&mut schedule[bytes..], &t, 4);
|
||||
schedule[bytes..].copy_from_slice(&t);
|
||||
bytes += 4;
|
||||
|
||||
for _ in 0..3 {
|
||||
t.copy_from_slice(&schedule[bytes - 4..]);
|
||||
xorr(&mut t, &schedule[bytes - 16..], 4);
|
||||
schedule[bytes..].copy_from_slice(&t);
|
||||
bytes += 4;
|
||||
}
|
||||
}
|
||||
|
||||
schedule
|
||||
}
|
||||
|
||||
fn shift_rows(state: &mut [u8]) {
|
||||
let temp = state.to_vec();
|
||||
(0..16).for_each(|i| state[i] = temp[SHIFT_ROWS_TABLE[i] as usize]);
|
||||
}
|
||||
|
||||
fn shift_rows_inv(state: &mut [u8]) {
|
||||
let temp = state.to_vec();
|
||||
(0..16).for_each(|i| state[i] = temp[SHIFT_ROWS_TABLE_INV[i] as usize]);
|
||||
}
|
||||
|
||||
fn mix_col(state: &mut [u8]) {
|
||||
let (a0, a1, a2, a3) = (state[0], state[1], state[2], state[3]);
|
||||
|
||||
state[0] = LOOKUP_G2[a0 as usize] ^ LOOKUP_G3[a1 as usize] ^ a2 ^ a3;
|
||||
state[1] = LOOKUP_G2[a1 as usize] ^ LOOKUP_G3[a2 as usize] ^ a3 ^ a0;
|
||||
state[2] = LOOKUP_G2[a2 as usize] ^ LOOKUP_G3[a3 as usize] ^ a0 ^ a1;
|
||||
state[3] = LOOKUP_G2[a3 as usize] ^ LOOKUP_G3[a0 as usize] ^ a1 ^ a2;
|
||||
}
|
||||
|
||||
fn mix_cols(state: &mut [u8]) {
|
||||
mix_col(&mut state[0..4]);
|
||||
mix_col(&mut state[4..8]);
|
||||
mix_col(&mut state[8..12]);
|
||||
mix_col(&mut state[12..16]);
|
||||
}
|
||||
|
||||
fn mix_col_inv(state: &mut [u8]) {
|
||||
let (a0, a1, a2, a3) = (state[0], state[1], state[2], state[3]);
|
||||
|
||||
state[0] = LOOKUP_G14[a0 as usize]
|
||||
^ LOOKUP_G9[a3 as usize]
|
||||
^ LOOKUP_G13[a2 as usize]
|
||||
^ LOOKUP_G11[a1 as usize];
|
||||
state[1] = LOOKUP_G14[a1 as usize]
|
||||
^ LOOKUP_G9[a0 as usize]
|
||||
^ LOOKUP_G13[a3 as usize]
|
||||
^ LOOKUP_G11[a2 as usize];
|
||||
state[2] = LOOKUP_G14[a2 as usize]
|
||||
^ LOOKUP_G9[a1 as usize]
|
||||
^ LOOKUP_G13[a0 as usize]
|
||||
^ LOOKUP_G11[a3 as usize];
|
||||
state[3] = LOOKUP_G14[a3 as usize]
|
||||
^ LOOKUP_G9[a2 as usize]
|
||||
^ LOOKUP_G13[a1 as usize]
|
||||
^ LOOKUP_G11[a0 as usize];
|
||||
}
|
||||
|
||||
fn mix_cols_inv(state: &mut [u8]) {
|
||||
mix_col_inv(&mut state[0..4]);
|
||||
mix_col_inv(&mut state[4..8]);
|
||||
mix_col_inv(&mut state[8..12]);
|
||||
mix_col_inv(&mut state[12..16]);
|
||||
}
|
||||
|
||||
fn oqs_aes128_enc_c(plaintext: &[u8], schedule: &[u8], ciphertext: &mut [u8]) {
|
||||
ciphertext.copy_from_slice(&plaintext[..16]);
|
||||
xor_round_key(ciphertext, schedule, 0);
|
||||
|
||||
for i in 1..10 {
|
||||
sub_bytes(ciphertext, 16);
|
||||
shift_rows(ciphertext);
|
||||
mix_cols(ciphertext);
|
||||
xor_round_key(ciphertext, schedule, i);
|
||||
}
|
||||
|
||||
sub_bytes(ciphertext, 16);
|
||||
shift_rows(ciphertext);
|
||||
xor_round_key(ciphertext, schedule, 10);
|
||||
}
|
||||
|
||||
pub fn oqs_mhy128_enc_c(plaintext: &[u8], schedule: &[u8], ciphertext: &mut [u8]) {
|
||||
ciphertext.copy_from_slice(&plaintext[..16]);
|
||||
xor_round_key(ciphertext, schedule, 0);
|
||||
|
||||
for i in 1..10 {
|
||||
sub_bytes_inv(ciphertext, 16);
|
||||
shift_rows_inv(ciphertext);
|
||||
mix_cols_inv(ciphertext);
|
||||
xor_round_key(ciphertext, schedule, i);
|
||||
}
|
||||
|
||||
sub_bytes_inv(ciphertext, 16);
|
||||
shift_rows_inv(ciphertext);
|
||||
xor_round_key(ciphertext, schedule, 10);
|
||||
}
|
||||
|
||||
fn oqs_aes128_dec_c(ciphertext: &[u8], schedule: &[u8], plaintext: &mut [u8]) {
|
||||
plaintext.copy_from_slice(&ciphertext[..16]);
|
||||
xor_round_key(plaintext, schedule, 10);
|
||||
shift_rows_inv(plaintext);
|
||||
sub_bytes_inv(plaintext, 16);
|
||||
|
||||
for i in 0..9 {
|
||||
xor_round_key(plaintext, schedule, 9 - i);
|
||||
mix_cols_inv(plaintext);
|
||||
shift_rows_inv(plaintext);
|
||||
sub_bytes_inv(plaintext, 16);
|
||||
}
|
||||
|
||||
xor_round_key(plaintext, schedule, 0);
|
||||
}
|
||||
|
||||
fn oqs_mhy128_dec_c(ciphertext: &[u8], schedule: &[u8], plaintext: &mut [u8]) {
|
||||
plaintext.copy_from_slice(&ciphertext[..16]);
|
||||
xor_round_key(plaintext, schedule, 10);
|
||||
shift_rows(plaintext);
|
||||
sub_bytes(plaintext, 16);
|
||||
|
||||
for i in 0..9 {
|
||||
xor_round_key(plaintext, schedule, 9 - i);
|
||||
mix_cols(plaintext);
|
||||
shift_rows(plaintext);
|
||||
sub_bytes(plaintext, 16);
|
||||
}
|
||||
|
||||
xor_round_key(plaintext, schedule, 0);
|
||||
}
|
92
nap_common/src/cryptography/ec2b/mod.rs
Normal file
92
nap_common/src/cryptography/ec2b/mod.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
|
||||
use magic::{AES_XORPAD_TABLE, KEY_XORPAD_TABLE};
|
||||
use mhy_aes::oqs_mhy128_enc_c;
|
||||
use std::io::Read;
|
||||
use thiserror::Error;
|
||||
|
||||
mod magic;
|
||||
mod mhy_aes;
|
||||
|
||||
const HEAD_MAGIC: u32 = 0x45633262; // "Ec2b"
|
||||
const KEY_SIZE: usize = 16;
|
||||
const DATA_SIZE: usize = 2048;
|
||||
|
||||
pub struct Ec2b {
|
||||
key: [u8; KEY_SIZE],
|
||||
data: [u8; DATA_SIZE],
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DecodeError {
|
||||
#[error("an I/O error occurred: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("magic mismatch, expected: {HEAD_MAGIC}, got: {0}")]
|
||||
MagicMismatch(u32),
|
||||
#[error("invalid key size, expected: {KEY_SIZE}, got: {0}")]
|
||||
InvalidKeySize(usize),
|
||||
#[error("invalid data size, expected: {DATA_SIZE}, got: {0}")]
|
||||
InvalidDataSize(usize),
|
||||
}
|
||||
|
||||
impl Ec2b {
|
||||
const XOR_MAGIC: u64 = 0xCEAC3B5A867837AC;
|
||||
|
||||
pub fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
|
||||
let magic = r.read_u32::<BigEndian>()?;
|
||||
matches!(magic, HEAD_MAGIC)
|
||||
.then_some(())
|
||||
.ok_or(DecodeError::MagicMismatch(magic))?;
|
||||
|
||||
let key_size = r.read_u32::<LittleEndian>()? as usize;
|
||||
matches!(key_size, KEY_SIZE)
|
||||
.then_some(())
|
||||
.ok_or(DecodeError::InvalidKeySize(key_size))?;
|
||||
|
||||
let mut key = [0u8; KEY_SIZE];
|
||||
r.read_exact(&mut key)?;
|
||||
|
||||
let data_size = r.read_u32::<LittleEndian>()? as usize;
|
||||
matches!(data_size, DATA_SIZE)
|
||||
.then_some(())
|
||||
.ok_or(DecodeError::InvalidDataSize(data_size))?;
|
||||
|
||||
let mut data = [0u8; DATA_SIZE];
|
||||
r.read_exact(&mut data)?;
|
||||
|
||||
Self::key_scramble(&mut key);
|
||||
(0..16).for_each(|i| key[i] ^= KEY_XORPAD_TABLE[i]);
|
||||
|
||||
Ok(Self { key, data })
|
||||
}
|
||||
|
||||
#[must_use] pub fn derive_seed(&self) -> u64 {
|
||||
let val = self
|
||||
.data
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap()))
|
||||
.fold(0xFFFFFFFFFFFFFFFF, |val, i| val ^ i);
|
||||
|
||||
let key_qword_0 = u64::from_le_bytes(self.key[0..8].try_into().unwrap());
|
||||
let key_qword_1 = u64::from_le_bytes(self.key[8..16].try_into().unwrap());
|
||||
|
||||
key_qword_1 ^ Self::XOR_MAGIC ^ val ^ key_qword_0
|
||||
}
|
||||
|
||||
fn key_scramble(key: &mut [u8]) {
|
||||
let mut round_keys = [0u8; 176];
|
||||
for round in 0..11 {
|
||||
for i in 0..16 {
|
||||
for j in 0..16 {
|
||||
let idx = (round << 8) + (i * 16) + j;
|
||||
round_keys[round * 16 + i] ^=
|
||||
AES_XORPAD_TABLE[1][idx] ^ AES_XORPAD_TABLE[0][idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut chip = [0u8; 16];
|
||||
oqs_mhy128_enc_c(key, &round_keys, &mut chip);
|
||||
|
||||
key.copy_from_slice(&chip);
|
||||
}
|
||||
}
|
7
nap_common/src/cryptography/mod.rs
Normal file
7
nap_common/src/cryptography/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
mod ec2b;
|
||||
mod rsa_util;
|
||||
mod xor;
|
||||
|
||||
pub use ec2b::Ec2b;
|
||||
pub use rsa_util::*;
|
||||
pub use xor::MhyXorpad;
|
48
nap_common/src/cryptography/rsa_util.rs
Normal file
48
nap_common/src/cryptography/rsa_util.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use rsa::pkcs1v15::SigningKey;
|
||||
use rsa::sha2::Sha256;
|
||||
use rsa::signature::{RandomizedSigner, SignatureEncoding};
|
||||
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
|
||||
|
||||
const CLIENT_PUBLIC_KEY: &[u8] = include_bytes!("../../client_public_key.der");
|
||||
const SERVER_PRIVATE_KEY: &[u8] = include_bytes!("../../server_private_key.der");
|
||||
const RSA_CHUNK_SIZE: usize = 117;
|
||||
|
||||
#[must_use]
|
||||
pub fn rsa_encrypt(data: &[u8]) -> Box<[u8]> {
|
||||
let public_key: RsaPublicKey =
|
||||
rsa::pkcs8::DecodePublicKey::from_public_key_der(CLIENT_PUBLIC_KEY)
|
||||
.expect("Failed to read public key from der");
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut result: Vec<u8> = Vec::new();
|
||||
for chunk in data.chunks(RSA_CHUNK_SIZE) {
|
||||
let encrypted_chunk = public_key
|
||||
.encrypt(&mut rng, Pkcs1v15Encrypt, chunk)
|
||||
.expect("Encryption failed");
|
||||
|
||||
result.extend(encrypted_chunk);
|
||||
}
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn rsa_decrypt(cipher: &[u8]) -> Vec<u8> {
|
||||
let private_key: RsaPrivateKey =
|
||||
rsa::pkcs8::DecodePrivateKey::from_pkcs8_der(SERVER_PRIVATE_KEY)
|
||||
.expect("Failed to read pkcs8 private key");
|
||||
|
||||
private_key
|
||||
.decrypt(Pkcs1v15Encrypt, cipher)
|
||||
.expect("Decryption failed")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn rsa_sign(data: &[u8]) -> Box<[u8]> {
|
||||
let private_key = rsa::pkcs8::DecodePrivateKey::from_pkcs8_der(SERVER_PRIVATE_KEY)
|
||||
.expect("Failed to read pkcs8 private key");
|
||||
let signing_key = SigningKey::<Sha256>::new(private_key);
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
signing_key.sign_with_rng(&mut rng, data).to_bytes()
|
||||
}
|
22
nap_common/src/cryptography/xor.rs
Normal file
22
nap_common/src/cryptography/xor.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use byteorder::ByteOrder;
|
||||
use rand_mt::Mt64;
|
||||
|
||||
const SIZE: usize = 4096;
|
||||
pub struct MhyXorpad([u8; SIZE]);
|
||||
|
||||
impl MhyXorpad {
|
||||
#[must_use]
|
||||
pub fn new<E: ByteOrder>(seed: u64) -> Self {
|
||||
let mut mt = Mt64::new(seed);
|
||||
let mut buf = [0u8; 4096];
|
||||
|
||||
(0..(SIZE >> 3)).for_each(|i| E::write_u64(&mut buf[i * 8..(i + 1) * 8], mt.next_u64()));
|
||||
Self(buf)
|
||||
}
|
||||
|
||||
pub fn xor(&self, buf: &mut [u8]) {
|
||||
buf.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| *v ^= self.0[i % SIZE]);
|
||||
}
|
||||
}
|
40
nap_common/src/database/mod.rs
Normal file
40
nap_common/src/database/mod.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{migrate, PgPool};
|
||||
|
||||
pub mod player_data;
|
||||
pub mod sdk_data;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DatabaseCredentials {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub host: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl ToString for DatabaseCredentials {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"postgres://{}:{}@{}/{}",
|
||||
&self.username, &self.password, &self.host, &self.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DatabaseCredentials {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
username: String::from("root"),
|
||||
password: String::from("root"),
|
||||
host: String::from("localhost:5432"),
|
||||
name: String::from("nap"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init(credentials: &DatabaseCredentials) -> Result<PgPool, sqlx::Error> {
|
||||
let pool = PgPool::connect(&credentials.to_string()).await?;
|
||||
migrate!("./migrations").run(&pool).await?;
|
||||
|
||||
Ok(pool)
|
||||
}
|
20
nap_common/src/database/player_data.rs
Normal file
20
nap_common/src/database/player_data.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
#[derive(FromRow, Debug)]
|
||||
pub struct DbUserUidRow {
|
||||
pub uid: i32,
|
||||
pub account_uid: String,
|
||||
pub ext: String,
|
||||
}
|
||||
|
||||
#[derive(FromRow, Debug)]
|
||||
pub struct DbPlayerDataRow {
|
||||
pub uid: i32,
|
||||
pub bin_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PlayerExtJsonData {
|
||||
pub reg_platform: u32,
|
||||
}
|
97
nap_common/src/database/sdk_data.rs
Normal file
97
nap_common/src/database/sdk_data.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use regex::Regex;
|
||||
use sqlx::FromRow;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::util;
|
||||
|
||||
#[derive(sqlx::Encode, sqlx::Decode)]
|
||||
pub struct Username(String);
|
||||
|
||||
impl Username {
|
||||
pub fn parse(username: String) -> Option<Self> {
|
||||
static ALLOWED_USERNAME_REGEX: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new("^[a-zA-Z0-9._@-]{6,25}$").unwrap());
|
||||
|
||||
ALLOWED_USERNAME_REGEX
|
||||
.is_match(&username)
|
||||
.then_some(Self(username))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Type<sqlx::Postgres> for Username {
|
||||
fn type_info() -> <sqlx::Postgres as sqlx::Database>::TypeInfo {
|
||||
<String as sqlx::Type<sqlx::Postgres>>::type_info()
|
||||
}
|
||||
|
||||
fn compatible(ty: &<sqlx::Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||
<String as sqlx::Type<sqlx::Postgres>>::compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PasswordError {
|
||||
#[error("password pair mismatch")]
|
||||
PairMismatch,
|
||||
#[error("user input doesn't meet requirements")]
|
||||
RequirementsMismatch,
|
||||
#[error("failed to generate password hash: {0}")]
|
||||
HashFailed(pbkdf2::password_hash::Error),
|
||||
}
|
||||
|
||||
#[derive(sqlx::Encode, sqlx::Decode)]
|
||||
pub struct Password(String);
|
||||
|
||||
impl Password {
|
||||
pub fn new(password: String, password_v2: String) -> Result<Self, PasswordError> {
|
||||
(password == password_v2)
|
||||
.then_some(())
|
||||
.ok_or(PasswordError::PairMismatch)?;
|
||||
|
||||
matches!(password.len(), 8..30)
|
||||
.then_some(())
|
||||
.ok_or(PasswordError::RequirementsMismatch)?;
|
||||
|
||||
let hash = util::hash_string(&password).map_err(|err| PasswordError::HashFailed(err))?;
|
||||
Ok(Self(hash))
|
||||
}
|
||||
|
||||
pub fn verify(&self, password: &str) -> bool {
|
||||
util::verify_hash(password, &self.0).is_some()
|
||||
}
|
||||
|
||||
pub fn as_hash_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Type<sqlx::Postgres> for Password {
|
||||
fn type_info() -> <sqlx::Postgres as sqlx::Database>::TypeInfo {
|
||||
<String as sqlx::Type<sqlx::Postgres>>::type_info()
|
||||
}
|
||||
|
||||
fn compatible(ty: &<sqlx::Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||
<String as sqlx::Type<sqlx::Postgres>>::compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct DbSdkAccountRow {
|
||||
pub uid: i32,
|
||||
pub token: String,
|
||||
pub username: Username,
|
||||
pub password: Password,
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct DbComboTokenRow {
|
||||
pub account_uid: String,
|
||||
pub token: String,
|
||||
pub device_id: String,
|
||||
}
|
8
nap_common/src/lib.rs
Normal file
8
nap_common/src/lib.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
pub mod constants;
|
||||
pub mod cryptography;
|
||||
pub mod database;
|
||||
mod logging;
|
||||
pub mod splash;
|
||||
pub mod util;
|
||||
|
||||
pub use logging::init_tracing;
|
6
nap_common/src/logging.rs
Normal file
6
nap_common/src/logging.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
pub fn init_tracing() {
|
||||
#[cfg(target_os = "windows")]
|
||||
ansi_term::enable_ansi_support().unwrap();
|
||||
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
}
|
5
nap_common/src/splash.rs
Normal file
5
nap_common/src/splash.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
use crate::constants::{CLIENT_VERSION, SERVER_VERSION};
|
||||
|
||||
pub fn print(service_type: &str) {
|
||||
println!("\n ____. ________ __________ _________\n | |____ ____ ____ \\______ \\ ____ ____ \\____ / / _____/\n | \\__ \\ / \\_/ __ \\ | | \\ / _ \\_/ __ \\ / / \\_____ \\ \n/\\__| |/ __ \\| | \\ ___/ | ` ( <_> ) ___/ / /_ / \\\n\\________(______/___|__/\\_____>_________/\\____/ \\_____> /_______/\\/________ /\n v{SERVER_VERSION} (game: {CLIENT_VERSION}) {service_type}\n");
|
||||
}
|
67
nap_common/src/util.rs
Normal file
67
nap_common/src/util.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use password_hash::{PasswordHash, PasswordHasher, SaltString};
|
||||
use pbkdf2::{Params, Pbkdf2};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
#[must_use]
|
||||
pub fn load_or_create_config<T>(path: &str) -> T
|
||||
where
|
||||
T: Default + Serialize + DeserializeOwned,
|
||||
{
|
||||
std::fs::read_to_string(path).map_or_else(
|
||||
|_| {
|
||||
let defaults = T::default();
|
||||
std::fs::write(path, toml::to_string(&defaults).unwrap()).unwrap();
|
||||
defaults
|
||||
},
|
||||
|data| toml::from_str(&data).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn open_secret_key() -> Result<File, std::io::Error> {
|
||||
File::open("assets/security/client_secret_key.ec2b")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn cur_timestamp_ms() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn cur_timestamp() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs() as u64
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn hash_string(content: &str) -> Result<String, pbkdf2::password_hash::Error> {
|
||||
let salt = SaltString::generate(rand::thread_rng());
|
||||
let hash = Pbkdf2.hash_password_customized(
|
||||
content.as_bytes(),
|
||||
None,
|
||||
None,
|
||||
Params {
|
||||
rounds: 10000,
|
||||
output_length: 32,
|
||||
},
|
||||
&salt,
|
||||
)?;
|
||||
|
||||
Ok(hash.serialize().to_string())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn verify_hash(content: &str, hash_str: &str) -> Option<()> {
|
||||
let hash = PasswordHash::new(hash_str).ok()?;
|
||||
hash.verify_password(&[&Pbkdf2], content).ok()
|
||||
}
|
16
nap_data/Cargo.toml
Normal file
16
nap_data/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "data"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
# Serialization
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
# Util
|
||||
paste.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
# Tracing
|
||||
tracing.workspace = true
|
45
nap_data/src/lib.rs
Normal file
45
nap_data/src/lib.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
pub mod tables;
|
||||
|
||||
use std::{collections::HashMap, sync::OnceLock};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AssetsConfig {
|
||||
pub filecfg_path: String,
|
||||
pub usm_keys_path: String,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DataLoadError {
|
||||
#[error("I/O error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("from_json failed for type {0}, error: {1}")]
|
||||
FromJsonError(String, serde_json::Error),
|
||||
}
|
||||
|
||||
static USM_KEY_MAP: OnceLock<HashMap<u32, u64>> = OnceLock::new();
|
||||
|
||||
pub fn init_data(config: &AssetsConfig) -> Result<(), DataLoadError> {
|
||||
tables::load_tables(&config.filecfg_path)?;
|
||||
if let Err(err) = load_usm_keys(&config.usm_keys_path) {
|
||||
tracing::warn!("failed to load USM keys, in-game cutscenes will not work! Reason: {err}");
|
||||
USM_KEY_MAP.set(HashMap::new()).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn usm_key_map() -> &'static HashMap<u32, u64> {
|
||||
USM_KEY_MAP.get().unwrap()
|
||||
}
|
||||
|
||||
fn load_usm_keys(path: &str) -> Result<(), DataLoadError> {
|
||||
let data = std::fs::read_to_string(path).map_err(|err| DataLoadError::IoError(err))?;
|
||||
let map = serde_json::from_str::<HashMap<u32, u64>>(&data)
|
||||
.map_err(|err| DataLoadError::FromJsonError(String::from("USMKeyMap"), err))?;
|
||||
|
||||
USM_KEY_MAP.set(map).unwrap();
|
||||
Ok(())
|
||||
}
|
17
nap_data/src/tables/avatar_base_template.rs
Normal file
17
nap_data/src/tables/avatar_base_template.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct AvatarBaseTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: u32,
|
||||
pub code_name: String,
|
||||
pub name: String,
|
||||
pub full_name: String,
|
||||
pub audio_event_replace_param: String,
|
||||
pub audio_bank: String,
|
||||
pub hit_types: Box<[u32]>,
|
||||
pub element_types: Box<[u32]>,
|
||||
pub gender: u32,
|
||||
pub camp: u32,
|
||||
}
|
46
nap_data/src/tables/mod.rs
Normal file
46
nap_data/src/tables/mod.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use paste::paste;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use super::DataLoadError;
|
||||
|
||||
macro_rules! template_tables {
|
||||
($($template_type:ident;)*) => {
|
||||
$(paste! {
|
||||
mod [<$template_type:snake>];
|
||||
pub use [<$template_type:snake>]::$template_type;
|
||||
})*
|
||||
|
||||
$(paste! {
|
||||
static [<$template_type:snake:upper _TB>]: OnceLock<Vec<$template_type>> = OnceLock::new();
|
||||
})*
|
||||
|
||||
pub(crate) fn load_tables(filecfg_path: &str) -> Result<(), DataLoadError> {
|
||||
$(paste! {
|
||||
let file_name = concat!(stringify!($template_type), "Tb.json");
|
||||
let path = format!("{filecfg_path}/{file_name}");
|
||||
|
||||
let data = std::fs::read_to_string(path)?;
|
||||
[<$template_type:snake:upper _TB>].set(serde_json::from_str(&data).map_err(|err| DataLoadError::FromJsonError(String::from(stringify!($template_type)), err))?).unwrap();
|
||||
})*
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
$(paste! {
|
||||
pub mod [<$template_type:snake _tb>] {
|
||||
pub fn iter() -> ::std::slice::Iter<'static, super::$template_type> {
|
||||
super::[<$template_type:snake:upper _TB>].get().unwrap().iter()
|
||||
}
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
template_tables! {
|
||||
AvatarBaseTemplate;
|
||||
UnlockConfigTemplate;
|
||||
SectionConfigTemplate;
|
||||
ProcedureConfigTemplate;
|
||||
PostGirlConfigTemplate;
|
||||
TrainingQuestTemplate;
|
||||
}
|
9
nap_data/src/tables/post_girl_config_template.rs
Normal file
9
nap_data/src/tables/post_girl_config_template.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct PostGirlConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: u32,
|
||||
pub name: String,
|
||||
}
|
14
nap_data/src/tables/procedure_config_template.rs
Normal file
14
nap_data/src/tables/procedure_config_template.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ProcedureConfigTemplate {
|
||||
#[serde(rename = "ProcedureID")]
|
||||
pub procedure_id: i32,
|
||||
pub procedure_type: u32,
|
||||
#[serde(rename = "ContentID")]
|
||||
pub content_id: String,
|
||||
pub jump_tos: Vec<i32>,
|
||||
pub procedure_banks: Vec<String>,
|
||||
pub procedure_event: String,
|
||||
}
|
12
nap_data/src/tables/section_config_template.rs
Normal file
12
nap_data/src/tables/section_config_template.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct SectionConfigTemplate {
|
||||
pub section_id: u32,
|
||||
pub photo_name: String,
|
||||
pub name: String,
|
||||
pub primary_entry_name: String,
|
||||
pub secondary_entry_name: String,
|
||||
pub section_name: String,
|
||||
}
|
9
nap_data/src/tables/training_quest_template.rs
Normal file
9
nap_data/src/tables/training_quest_template.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct TrainingQuestTemplate {
|
||||
pub id: u32,
|
||||
pub training_type: u32,
|
||||
pub battle_event_id: u32,
|
||||
}
|
9
nap_data/src/tables/unlock_config_template.rs
Normal file
9
nap_data/src/tables/unlock_config_template.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct UnlockConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
}
|
42
nap_gameserver/Cargo.toml
Normal file
42
nap_gameserver/Cargo.toml
Normal file
|
@ -0,0 +1,42 @@
|
|||
[package]
|
||||
name = "nap-gameserver"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
# Runtime
|
||||
tokio.workspace = true
|
||||
tokio-util.workspace = true
|
||||
|
||||
# Serialization
|
||||
prost.workspace = true
|
||||
prost-types.workspace = true
|
||||
rbase64.workspace = true
|
||||
toml.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
# Database
|
||||
sqlx.workspace = true
|
||||
|
||||
# Util
|
||||
thiserror.workspace = true
|
||||
paste.workspace = true
|
||||
byteorder.workspace = true
|
||||
hex.workspace = true
|
||||
rand.workspace = true
|
||||
atomic_enum.workspace = true
|
||||
num_enum.workspace = true
|
||||
dashmap.workspace = true
|
||||
|
||||
# Tracing
|
||||
tracing.workspace = true
|
||||
tracing-futures.workspace = true
|
||||
tracing-log.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing-bunyan-formatter.workspace = true
|
||||
|
||||
# Internal
|
||||
common.workspace = true
|
||||
data.workspace = true
|
||||
proto.workspace = true
|
26
nap_gameserver/src/config.rs
Normal file
26
nap_gameserver/src/config.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use common::database::DatabaseCredentials;
|
||||
use data::AssetsConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct NapGSConfig {
|
||||
pub tcp_listen_addr: String,
|
||||
pub player_save_period_seconds: u64,
|
||||
#[serde(rename = "database")]
|
||||
pub database_credentials: DatabaseCredentials,
|
||||
pub assets: AssetsConfig,
|
||||
}
|
||||
|
||||
impl Default for NapGSConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tcp_listen_addr: String::from("0.0.0.0:20501"),
|
||||
player_save_period_seconds: 30,
|
||||
database_credentials: DatabaseCredentials::default(),
|
||||
assets: AssetsConfig {
|
||||
filecfg_path: String::from("assets/FileCfg"),
|
||||
usm_keys_path: String::from("assets/VideoUSMEncKeys.json"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
94
nap_gameserver/src/database/mod.rs
Normal file
94
nap_gameserver/src/database/mod.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use common::database::{
|
||||
player_data::{DbPlayerDataRow, DbUserUidRow, PlayerExtJsonData},
|
||||
sdk_data::DbComboTokenRow,
|
||||
};
|
||||
use sqlx::{query, query_as, PgPool};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DbError {
|
||||
#[error("SQL error: {0}")]
|
||||
SqlxError(#[from] sqlx::Error),
|
||||
#[error("entry not found")]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
pub async fn select_combo_token_by_account(
|
||||
pool: &PgPool,
|
||||
account_uid: &str,
|
||||
) -> Result<DbComboTokenRow, DbError> {
|
||||
query_as("SELECT * from t_combo_token where account_uid = ($1)")
|
||||
.bind(account_uid)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
.ok_or(DbError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn select_player_uid_by_account(
|
||||
pool: &PgPool,
|
||||
account_uid: &str,
|
||||
) -> Result<DbUserUidRow, DbError> {
|
||||
query_as("SELECT * from t_user_uid where account_uid = ($1)")
|
||||
.bind(account_uid)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
.ok_or(DbError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn insert_player_uid_by_account(
|
||||
pool: &PgPool,
|
||||
account_uid: &str,
|
||||
platform: u32,
|
||||
) -> Result<DbUserUidRow, DbError> {
|
||||
let ext = serde_json::to_string(&PlayerExtJsonData {
|
||||
reg_platform: platform,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Ok(
|
||||
query_as("INSERT INTO t_user_uid (account_uid, ext) VALUES ($1, $2) RETURNING *")
|
||||
.bind(account_uid)
|
||||
.bind(ext)
|
||||
.fetch_one(pool)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn select_player_data_by_uid(
|
||||
pool: &PgPool,
|
||||
uid: i32,
|
||||
) -> Result<DbPlayerDataRow, DbError> {
|
||||
query_as("SELECT * from t_player_data where uid = ($1)")
|
||||
.bind(uid)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
.ok_or(DbError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn insert_player_data_by_uid(
|
||||
pool: &PgPool,
|
||||
uid: i32,
|
||||
bin_data: Vec<u8>,
|
||||
) -> Result<(), DbError> {
|
||||
query("INSERT into t_player_data VALUES ($1, $2)")
|
||||
.bind(uid)
|
||||
.bind(bin_data)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_player_data_by_uid(
|
||||
pool: &PgPool,
|
||||
uid: i32,
|
||||
bin_data: Vec<u8>,
|
||||
) -> Result<(), DbError> {
|
||||
query("UPDATE t_player_data SET bin_data = ($1) WHERE uid = ($2)")
|
||||
.bind(bin_data)
|
||||
.bind(uid)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
25
nap_gameserver/src/handlers/abyss.rs
Normal file
25
nap_gameserver/src/handlers/abyss.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_abyss_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetAbyssInfoCsReq,
|
||||
) -> NetResult<GetAbyssInfoScRsp> {
|
||||
Ok(GetAbyssInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
abyss_info: Some(AbyssInfo::default()),
|
||||
abyss_group_list: Vec::new(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_completed_abyss_group_list(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetCompletedAbyssGroupListCsReq,
|
||||
) -> NetResult<GetCompletedAbyssGroupListScRsp> {
|
||||
Ok(GetCompletedAbyssGroupListScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
23
nap_gameserver/src/handlers/activity.rs
Normal file
23
nap_gameserver/src/handlers/activity.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_activity_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetActivityDataCsReq,
|
||||
) -> NetResult<GetActivityDataScRsp> {
|
||||
Ok(GetActivityDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_web_activity_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetWebActivityDataCsReq,
|
||||
) -> NetResult<GetWebActivityDataScRsp> {
|
||||
Ok(GetWebActivityDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/arcade.rs
Normal file
12
nap_gameserver/src/handlers/arcade.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_arcade_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetArcadeDataCsReq,
|
||||
) -> NetResult<GetArcadeDataScRsp> {
|
||||
Ok(GetArcadeDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
30
nap_gameserver/src/handlers/avatar.rs
Normal file
30
nap_gameserver/src/handlers/avatar.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use crate::logic::role::Avatar;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_avatar_data(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: GetAvatarDataCsReq,
|
||||
) -> NetResult<GetAvatarDataScRsp> {
|
||||
Ok(GetAvatarDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
avatar_list: player
|
||||
.role_model
|
||||
.avatar_list
|
||||
.iter()
|
||||
.map(Avatar::to_client)
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_buddy_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetBuddyDataCsReq,
|
||||
) -> NetResult<GetBuddyDataScRsp> {
|
||||
Ok(GetBuddyDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/battle_pass.rs
Normal file
12
nap_gameserver/src/handlers/battle_pass.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_battle_pass_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetBattlePassDataCsReq,
|
||||
) -> NetResult<GetBattlePassDataScRsp> {
|
||||
Ok(GetBattlePassDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
23
nap_gameserver/src/handlers/cafe.rs
Normal file
23
nap_gameserver/src/handlers/cafe.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_cafe_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetCafeDataCsReq,
|
||||
) -> NetResult<GetCafeDataScRsp> {
|
||||
Ok(GetCafeDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
cafe_data: Some(CafeData::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_reward_buff_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetRewardBuffDataCsReq,
|
||||
) -> NetResult<GetRewardBuffDataScRsp> {
|
||||
Ok(GetRewardBuffDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
info: Some(RewardBuffData::default()),
|
||||
})
|
||||
}
|
23
nap_gameserver/src/handlers/character_quest.rs
Normal file
23
nap_gameserver/src/handlers/character_quest.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_character_quest_list(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetCharacterQuestListCsReq,
|
||||
) -> NetResult<GetCharacterQuestListScRsp> {
|
||||
Ok(GetCharacterQuestListScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_photo_wall_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetPhotoWallDataCsReq,
|
||||
) -> NetResult<GetPhotoWallDataScRsp> {
|
||||
Ok(GetPhotoWallDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
159
nap_gameserver/src/handlers/client_systems.rs
Normal file
159
nap_gameserver/src/handlers/client_systems.rs
Normal file
|
@ -0,0 +1,159 @@
|
|||
use crate::logic::{EOperator, ESystem};
|
||||
|
||||
use super::*;
|
||||
|
||||
use data::tables;
|
||||
|
||||
pub async fn on_get_tips_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: GetTipsInfoCsReq,
|
||||
) -> NetResult<GetTipsInfoScRsp> {
|
||||
Ok(GetTipsInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
tips_info: Some(TipsInfo::default()),
|
||||
ofolagfmcmo: req.ofolagfmcmo, // tips group type
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_client_systems_info(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: GetClientSystemsInfoCsReq,
|
||||
) -> NetResult<GetClientSystemsInfoScRsp> {
|
||||
Ok(GetClientSystemsInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
info: Some(ClientSystemsInfo {
|
||||
post_girl_data: Some(PostGirlData {
|
||||
selected_post_girl_id_list: tables::post_girl_config_template_tb::iter()
|
||||
.map(|template| template.id)
|
||||
.collect(),
|
||||
post_girl_list: tables::post_girl_config_template_tb::iter()
|
||||
.map(|template| PostGirlItem {
|
||||
template_id: template.id,
|
||||
unlock_time: 1000,
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
unlock_data: Some(player.lock_model.to_client()),
|
||||
hbhfjgbahgf: Some(Aboegnnepmi::default()),
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_news_stand_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetNewsStandDataCsReq,
|
||||
) -> NetResult<GetNewsStandDataScRsp> {
|
||||
Ok(GetNewsStandDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
news_stand_data: Some(NewsStandData::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_trashbin_hermit_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetTrashbinHermitDataCsReq,
|
||||
) -> NetResult<GetTrashbinHermitDataScRsp> {
|
||||
Ok(GetTrashbinHermitDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
trashbin_hermit_data: Some(TrashbinHermitData::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_exploration_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetExplorationDataCsReq,
|
||||
) -> NetResult<GetExplorationDataScRsp> {
|
||||
Ok(GetExplorationDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_report_ui_layout_platform(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: ReportUiLayoutPlatformCsReq,
|
||||
) -> NetResult<ReportUiLayoutPlatformScRsp> {
|
||||
Ok(ReportUiLayoutPlatformScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_unlock_newbie_group(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: UnlockNewbieGroupCsReq,
|
||||
) -> NetResult<UnlockNewbieGroupScRsp> {
|
||||
Ok(UnlockNewbieGroupScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
group_id: req.group_id,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_battle_report(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: BattleReportCsReq,
|
||||
) -> NetResult<BattleReportScRsp> {
|
||||
Ok(BattleReportScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_player_operation(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: PlayerOperationCsReq,
|
||||
) -> NetResult<PlayerOperationScRsp> {
|
||||
tracing::info!(
|
||||
"PlayerOperation(system={:?}, operator={:?}, param={})",
|
||||
ESystem::from(req.system),
|
||||
EOperator::from(req.operator),
|
||||
req.param
|
||||
);
|
||||
|
||||
Ok(PlayerOperationScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_pop_up_window_seen(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: PopUpWindowSeenCsReq,
|
||||
) -> NetResult<PopUpWindowSeenScRsp> {
|
||||
Ok(PopUpWindowSeenScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
popup_group_id_list: req.popup_group_id_list,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_report_system_settings_change(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: ReportSystemSettingsChangeCsReq,
|
||||
) -> NetResult<ReportSystemSettingsChangeScRsp> {
|
||||
tracing::info!("system settings change {req:?}");
|
||||
|
||||
Ok(ReportSystemSettingsChangeScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_interact_with_scene_object(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: InteractWithSceneObjectCsReq,
|
||||
) -> NetResult<InteractWithSceneObjectScRsp> {
|
||||
// this request is used for interaction with STATIC scene objects (not controlled by server, e.g. door in workshop)
|
||||
Ok(InteractWithSceneObjectScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
34
nap_gameserver/src/handlers/collect.rs
Normal file
34
nap_gameserver/src/handlers/collect.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_collect_map(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetCollectMapCsReq,
|
||||
) -> NetResult<GetCollectMapScRsp> {
|
||||
Ok(GetCollectMapScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
collect_map: Some(CollectMap::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_workbench_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetWorkbenchInfoCsReq,
|
||||
) -> NetResult<GetWorkbenchInfoScRsp> {
|
||||
Ok(GetWorkbenchInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
workbench_info: Some(WorkbenchInfo::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_abyss_reward_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetAbyssRewardDataCsReq,
|
||||
) -> NetResult<GetAbyssRewardDataScRsp> {
|
||||
Ok(GetAbyssRewardDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
abyss_reward_data: Some(AbyssRewardData::default()),
|
||||
})
|
||||
}
|
36
nap_gameserver/src/handlers/core/error.rs
Normal file
36
nap_gameserver/src/handlers/core/error.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use proto::Retcode;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::logic::game::LogicError;
|
||||
|
||||
pub type NetResult<T> = Result<T, NetError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PacketHandlingError {
|
||||
#[error("protobuf decode failed: {0}")]
|
||||
DecodeFailed(#[from] prost::DecodeError),
|
||||
#[error("I/O error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("net error: {0}")]
|
||||
Net(#[from] NetError),
|
||||
#[error("soft logout performed")]
|
||||
Logout,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum NetError {
|
||||
#[error("I/O error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("logic error: {0}")]
|
||||
LogicError(#[from] LogicError),
|
||||
#[error("retcode: {0:?}")]
|
||||
ErrCode(Retcode),
|
||||
#[error("soft logout performed")]
|
||||
Logout,
|
||||
}
|
||||
|
||||
impl From<Retcode> for NetError {
|
||||
fn from(value: Retcode) -> Self {
|
||||
Self::ErrCode(value)
|
||||
}
|
||||
}
|
126
nap_gameserver/src/handlers/core/macros.rs
Normal file
126
nap_gameserver/src/handlers/core/macros.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
#[macro_export]
|
||||
macro_rules! auth_req_handlers {
|
||||
($($module:ident::$name:ident;)*) => {
|
||||
pub async fn handle_auth_request(session: &crate::net::NetSession, packet: &crate::net::NetPacket, state: &crate::ServerState) -> Result<bool, crate::handlers::core::PacketHandlingError> {
|
||||
use ::prost::Message;
|
||||
use crate::handlers::core::NetError;
|
||||
use crate::handlers::core::PacketHandlingError;
|
||||
::paste::paste! {
|
||||
match packet.cmd_id {
|
||||
$(
|
||||
::proto::[<$name CsReq>]::CMD_ID => {
|
||||
let mut req = ::proto::[<$name CsReq>]::decode(&*packet.body)?;
|
||||
req.xor_fields();
|
||||
|
||||
let rsp = match crate::handlers::$module::[<on_ $name:snake>](&session, &state.player_mgr, req).await {
|
||||
Ok(rsp) => {
|
||||
::tracing::info!(concat!("[LOGIN] successfully handled request ", stringify!($name)));
|
||||
rsp
|
||||
},
|
||||
Err(NetError::ErrCode(retcode)) => {
|
||||
::tracing::info!("[LOGIN] request {} was handled, retcode: {retcode:?}", stringify!($name));
|
||||
[<$name ScRsp>] {
|
||||
retcode: retcode.into(),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
Err(err) => return Err(PacketHandlingError::Net(err)),
|
||||
};
|
||||
|
||||
session.send_rsp(packet.head.packet_id, rsp).await?;
|
||||
Ok(true)
|
||||
}
|
||||
)*
|
||||
_ => Ok(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! req_handlers {
|
||||
($($module:ident::$name:ident;)*) => {
|
||||
pub async fn handle_request(session: &crate::net::NetSession, packet: &crate::net::NetPacket, state: &crate::ServerState) -> Result<bool, crate::handlers::core::PacketHandlingError> {
|
||||
use ::prost::Message;
|
||||
use crate::handlers::core::NetError;
|
||||
use crate::handlers::core::PacketHandlingError;
|
||||
::paste::paste! {
|
||||
match packet.cmd_id {
|
||||
$(
|
||||
::proto::[<$name CsReq>]::CMD_ID => {
|
||||
let player_uid = *session.player_uid().unwrap(); // Should never be None here
|
||||
let Some(player_lock) = state.player_mgr.get_player(player_uid).await else {
|
||||
::tracing::error!("PlayerManager::get_player returned None, uid={player_uid}");
|
||||
return Ok(true);
|
||||
};
|
||||
|
||||
let mut req = ::proto::[<$name CsReq>]::decode(&*packet.body)?;
|
||||
req.xor_fields();
|
||||
|
||||
let rsp = match crate::handlers::$module::[<on_ $name:snake>](&session, &mut *player_lock.lock().await, req).await {
|
||||
Ok(rsp) => {
|
||||
::tracing::info!(concat!("successfully handled request ", stringify!($name)));
|
||||
rsp
|
||||
}
|
||||
Err(NetError::ErrCode(retcode)) => {
|
||||
::tracing::info!("request {} was handled, retcode: {retcode:?}", stringify!($name));
|
||||
[<$name ScRsp>] {
|
||||
retcode: retcode.into(),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
Err(err) => return Err(PacketHandlingError::Net(err)),
|
||||
};
|
||||
|
||||
session.send_rsp(packet.head.packet_id, rsp).await?;
|
||||
Ok(true)
|
||||
}
|
||||
)*
|
||||
_ => Ok(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! notify_handlers {
|
||||
($($module:ident::$name:ident;)*) => {
|
||||
pub async fn handle_notify(session: &crate::net::NetSession, packet: &crate::net::NetPacket, state: &crate::ServerState) -> Result<bool, crate::handlers::core::PacketHandlingError> {
|
||||
use ::prost::Message;
|
||||
use crate::handlers::core::NetError;
|
||||
use crate::handlers::core::PacketHandlingError;
|
||||
::paste::paste! {
|
||||
match packet.cmd_id {
|
||||
$(
|
||||
::proto::[<$name Notify>]::CMD_ID => {
|
||||
let player_uid = *session.player_uid().unwrap(); // Should never be None here
|
||||
let Some(player_lock) = state.player_mgr.get_player(player_uid).await else {
|
||||
::tracing::error!("PlayerManager::get_player returned None, uid={player_uid}");
|
||||
return Ok(true);
|
||||
};
|
||||
|
||||
let mut ntf = ::proto::[<$name Notify>]::decode(&*packet.body)?;
|
||||
ntf.xor_fields();
|
||||
|
||||
match crate::handlers::$module::[<on_ $name:snake>](session, &mut *player_lock.lock().await, ntf).await {
|
||||
Ok(()) => (),
|
||||
Err(NetError::Logout) => return Err(PacketHandlingError::Logout),
|
||||
Err(err) => return Err(PacketHandlingError::Net(err)),
|
||||
}
|
||||
|
||||
::tracing::info!("successfully handled notify {}", stringify!($name));
|
||||
Ok(true)
|
||||
}
|
||||
)*
|
||||
_ => Ok(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use auth_req_handlers;
|
||||
pub use notify_handlers;
|
||||
pub use req_handlers;
|
5
nap_gameserver/src/handlers/core/mod.rs
Normal file
5
nap_gameserver/src/handlers/core/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod error;
|
||||
mod macros;
|
||||
|
||||
pub use error::{NetError, NetResult, PacketHandlingError};
|
||||
pub use macros::{auth_req_handlers, notify_handlers, req_handlers};
|
12
nap_gameserver/src/handlers/daily_challenge.rs
Normal file
12
nap_gameserver/src/handlers/daily_challenge.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_daily_challenge_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetDailyChallengeInfoCsReq,
|
||||
) -> NetResult<GetDailyChallengeInfoScRsp> {
|
||||
Ok(GetDailyChallengeInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
info: Some(DailyChallengeInfo::default()),
|
||||
})
|
||||
}
|
23
nap_gameserver/src/handlers/embattles.rs
Normal file
23
nap_gameserver/src/handlers/embattles.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_embattles_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetEmbattlesDataCsReq,
|
||||
) -> NetResult<GetEmbattlesDataScRsp> {
|
||||
Ok(GetEmbattlesDataScRsp {
|
||||
embattles_data: Some(EmbattlesData::default()),
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_report_battle_team(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: ReportBattleTeamCsReq,
|
||||
) -> NetResult<ReportBattleTeamScRsp> {
|
||||
Ok(ReportBattleTeamScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/fairy.rs
Normal file
12
nap_gameserver/src/handlers/fairy.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_fairy_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetFairyInfoCsReq,
|
||||
) -> NetResult<GetFairyInfoScRsp> {
|
||||
Ok(GetFairyInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
info: Some(FairyInfo::default()),
|
||||
})
|
||||
}
|
25
nap_gameserver/src/handlers/friend.rs
Normal file
25
nap_gameserver/src/handlers/friend.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_friend_list(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetFriendListCsReq,
|
||||
) -> NetResult<GetFriendListScRsp> {
|
||||
Ok(GetFriendListScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_friend_limit_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetFriendLimitInfoCsReq,
|
||||
) -> NetResult<GetFriendLimitInfoScRsp> {
|
||||
Ok(GetFriendLimitInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
ngaiiafngbk: 30,
|
||||
ajndiihdlfa: 300,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
13
nap_gameserver/src/handlers/gacha.rs
Normal file
13
nap_gameserver/src/handlers/gacha.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_gacha_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: GetGachaDataCsReq,
|
||||
) -> NetResult<GetGachaDataScRsp> {
|
||||
Ok(GetGachaDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
gacha_type: req.gacha_type,
|
||||
gacha_data: Some(GachaData::default()),
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/hadal_zone.rs
Normal file
12
nap_gameserver/src/handlers/hadal_zone.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_hadal_zone_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetHadalZoneDataCsReq,
|
||||
) -> NetResult<GetHadalZoneDataScRsp> {
|
||||
Ok(GetHadalZoneDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
15
nap_gameserver/src/handlers/item.rs
Normal file
15
nap_gameserver/src/handlers/item.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_item_data(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: GetItemDataCsReq,
|
||||
) -> NetResult<GetItemDataScRsp> {
|
||||
let item_model = &player.item_model;
|
||||
|
||||
Ok(GetItemDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
resource_list: item_model.resources.iter().map(|i| i.to_client()).collect(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
59
nap_gameserver/src/handlers/login.rs
Normal file
59
nap_gameserver/src/handlers/login.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use common::cryptography::{rsa_decrypt, rsa_encrypt, rsa_sign};
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::{logic::player::PlayerManager, net::NetSessionState};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_player_get_token(
|
||||
session: &NetSession,
|
||||
player_mgr: &PlayerManager,
|
||||
req: PlayerGetTokenCsReq,
|
||||
) -> NetResult<PlayerGetTokenScRsp> {
|
||||
session.set_state(NetSessionState::PlayerGetTokenCsReq);
|
||||
|
||||
let uid = player_mgr
|
||||
.authorize(&req.account_uid, &req.token, req.platform_type)
|
||||
.await?;
|
||||
|
||||
let client_rand_key = rbase64::decode(&req.client_rand_key).map_err(|_| Retcode::RetFail)?;
|
||||
let client_rand_key = u64::from_le_bytes(rsa_decrypt(&client_rand_key).try_into().unwrap());
|
||||
let server_rand_key = rand::thread_rng().next_u64();
|
||||
|
||||
session.set_session_key(client_rand_key ^ server_rand_key);
|
||||
session.set_account_uid(req.account_uid);
|
||||
session.set_player_uid(uid);
|
||||
session.set_state(NetSessionState::PlayerGetTokenScRsp);
|
||||
|
||||
Ok(PlayerGetTokenScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
uid,
|
||||
server_rand_key: rbase64::encode(&rsa_encrypt(&server_rand_key.to_le_bytes())),
|
||||
sign: rbase64::encode(&rsa_sign(&server_rand_key.to_le_bytes())),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_player_login(
|
||||
session: &NetSession,
|
||||
player_mgr: &PlayerManager,
|
||||
_req: PlayerLoginCsReq,
|
||||
) -> NetResult<PlayerLoginScRsp> {
|
||||
session.set_state(NetSessionState::PlayerLoginCsReq);
|
||||
|
||||
let player_uid = *session.player_uid().ok_or(Retcode::RetFail)?;
|
||||
let player_lock = player_mgr
|
||||
.get_player(player_uid)
|
||||
.await
|
||||
.ok_or(Retcode::RetFail)?;
|
||||
|
||||
let mut player = player_lock.lock().await;
|
||||
player.set_current_session(session.id());
|
||||
player.on_login();
|
||||
|
||||
session.set_state(NetSessionState::StartBasicsReq);
|
||||
Ok(PlayerLoginScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/mail.rs
Normal file
12
nap_gameserver/src/handlers/mail.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_player_mails(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetPlayerMailsCsReq,
|
||||
) -> NetResult<GetPlayerMailsScRsp> {
|
||||
Ok(GetPlayerMailsScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/main_city_revival.rs
Normal file
12
nap_gameserver/src/handlers/main_city_revival.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_main_city_revival_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetMainCityRevivalDataCsReq,
|
||||
) -> NetResult<GetMainCityRevivalDataScRsp> {
|
||||
Ok(GetMainCityRevivalDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
main_city_revival: Some(MainCityRevivalData::default()),
|
||||
})
|
||||
}
|
34
nap_gameserver/src/handlers/misc.rs
Normal file
34
nap_gameserver/src/handlers/misc.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use common::util;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_server_timestamp(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetServerTimestampCsReq,
|
||||
) -> NetResult<GetServerTimestampScRsp> {
|
||||
Ok(GetServerTimestampScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
timestamp: util::cur_timestamp_ms(),
|
||||
utc_offset: 3,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_authkey(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetAuthkeyCsReq,
|
||||
) -> NetResult<GetAuthkeyScRsp> {
|
||||
Ok(GetAuthkeyScRsp::default())
|
||||
}
|
||||
|
||||
pub async fn on_get_cut_scene_key_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetCutSceneKeyInfoCsReq,
|
||||
) -> NetResult<GetCutSceneKeyInfoScRsp> {
|
||||
Ok(GetCutSceneKeyInfoScRsp {
|
||||
key_map: data::usm_key_map().clone(),
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
117
nap_gameserver/src/handlers/mod.rs
Normal file
117
nap_gameserver/src/handlers/mod.rs
Normal file
|
@ -0,0 +1,117 @@
|
|||
mod abyss;
|
||||
mod activity;
|
||||
mod arcade;
|
||||
mod avatar;
|
||||
mod battle_pass;
|
||||
mod cafe;
|
||||
mod character_quest;
|
||||
mod client_systems;
|
||||
mod collect;
|
||||
mod daily_challenge;
|
||||
mod embattles;
|
||||
mod fairy;
|
||||
mod friend;
|
||||
mod gacha;
|
||||
mod hadal_zone;
|
||||
mod item;
|
||||
mod login;
|
||||
mod mail;
|
||||
mod main_city_revival;
|
||||
mod misc;
|
||||
mod month_card;
|
||||
mod perform;
|
||||
mod player;
|
||||
mod private_message;
|
||||
mod quest;
|
||||
mod ramen;
|
||||
mod vhs_store;
|
||||
mod world;
|
||||
|
||||
mod core;
|
||||
|
||||
use crate::logic::Player;
|
||||
use core::NetResult;
|
||||
use core::{auth_req_handlers, notify_handlers, req_handlers};
|
||||
|
||||
pub use core::PacketHandlingError;
|
||||
|
||||
use crate::net::NetSession;
|
||||
use proto::*;
|
||||
|
||||
auth_req_handlers! {
|
||||
login::PlayerGetToken;
|
||||
login::PlayerLogin;
|
||||
}
|
||||
|
||||
req_handlers! {
|
||||
player::GetPlayerBasicInfo;
|
||||
player::CreateRole;
|
||||
player::GetPlayerTransaction;
|
||||
item::GetItemData;
|
||||
avatar::GetAvatarData;
|
||||
avatar::GetBuddyData;
|
||||
quest::GetQuestData;
|
||||
quest::GetYorozuyaInfo;
|
||||
quest::GetArchiveInfo;
|
||||
abyss::GetAbyssInfo;
|
||||
gacha::GetGachaData;
|
||||
ramen::GetRamenData;
|
||||
cafe::GetCafeData;
|
||||
cafe::GetRewardBuffData;
|
||||
mail::GetPlayerMails;
|
||||
fairy::GetFairyInfo;
|
||||
client_systems::GetTipsInfo;
|
||||
client_systems::GetClientSystemsInfo;
|
||||
private_message::GetPrivateMessageData;
|
||||
collect::GetCollectMap;
|
||||
collect::GetWorkbenchInfo;
|
||||
collect::GetAbyssRewardData;
|
||||
vhs_store::GetVhsStoreInfo;
|
||||
activity::GetActivityData;
|
||||
activity::GetWebActivityData;
|
||||
embattles::GetEmbattlesData;
|
||||
client_systems::GetNewsStandData;
|
||||
client_systems::GetTrashbinHermitData;
|
||||
client_systems::GetExplorationData;
|
||||
main_city_revival::GetMainCityRevivalData;
|
||||
arcade::GetArcadeData;
|
||||
battle_pass::GetBattlePassData;
|
||||
hadal_zone::GetHadalZoneData;
|
||||
daily_challenge::GetDailyChallengeInfo;
|
||||
abyss::GetCompletedAbyssGroupList;
|
||||
friend::GetFriendList;
|
||||
friend::GetFriendLimitInfo;
|
||||
character_quest::GetCharacterQuestList;
|
||||
character_quest::GetPhotoWallData;
|
||||
month_card::GetMonthCardDayReward;
|
||||
world::EnterWorld;
|
||||
world::EnterSection;
|
||||
world::SavePosInMainCity;
|
||||
world::WorldInitFinish;
|
||||
world::AdvanceBeginnerProcedure;
|
||||
world::BeginnerBattleBegin;
|
||||
world::BeginnerBattleEnd;
|
||||
world::BeginnerBattleRebegin;
|
||||
world::StartTrialFightingMission;
|
||||
world::EndBattle;
|
||||
world::LeaveCurDungeon;
|
||||
client_systems::ReportUiLayoutPlatform;
|
||||
client_systems::PlayerOperation;
|
||||
client_systems::UnlockNewbieGroup;
|
||||
client_systems::BattleReport;
|
||||
client_systems::PopUpWindowSeen;
|
||||
client_systems::ReportSystemSettingsChange;
|
||||
client_systems::InteractWithSceneObject;
|
||||
perform::PerformTrigger;
|
||||
perform::PerformEnd;
|
||||
perform::PerformJump;
|
||||
misc::GetAuthkey;
|
||||
misc::GetServerTimestamp;
|
||||
misc::GetCutSceneKeyInfo;
|
||||
embattles::ReportBattleTeam;
|
||||
}
|
||||
|
||||
notify_handlers! {
|
||||
player::KeepAlive;
|
||||
player::PlayerLogout;
|
||||
}
|
12
nap_gameserver/src/handlers/month_card.rs
Normal file
12
nap_gameserver/src/handlers/month_card.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_month_card_day_reward(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetMonthCardDayRewardCsReq,
|
||||
) -> NetResult<GetMonthCardDayRewardScRsp> {
|
||||
Ok(GetMonthCardDayRewardScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
57
nap_gameserver/src/handlers/perform.rs
Normal file
57
nap_gameserver/src/handlers/perform.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use super::core::NetError;
|
||||
|
||||
use crate::logic::{
|
||||
game::{GameInstance, LogicError},
|
||||
procedure::ProcedureAction,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_perform_trigger(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: PerformTriggerCsReq,
|
||||
) -> NetResult<PerformTriggerScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::PerformTrigger)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
Ok(PerformTriggerScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
perform_uid: ((req.perform_type as i64) << 32) | req.perform_id as i64,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_perform_end(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: PerformEndCsReq,
|
||||
) -> NetResult<PerformEndScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::PerformEnd)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
Ok(PerformEndScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_perform_jump(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: PerformJumpCsReq,
|
||||
) -> NetResult<PerformJumpScRsp> {
|
||||
Ok(PerformJumpScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
75
nap_gameserver/src/handlers/player.rs
Normal file
75
nap_gameserver/src/handlers/player.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use crate::logic::game::{GameInstance, LogicError};
|
||||
use crate::logic::procedure::ProcedureAction;
|
||||
|
||||
use super::core::NetError;
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_player_basic_info(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: GetPlayerBasicInfoCsReq,
|
||||
) -> NetResult<GetPlayerBasicInfoScRsp> {
|
||||
Ok(GetPlayerBasicInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
basic_info: Some(player.basic_data_model.player_basic_info()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_create_role(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: CreateRoleCsReq,
|
||||
) -> NetResult<CreateRoleScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::SelectRole)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
player.set_frontend_avatar(req.avatar_id as i32)?;
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
basic_info: Some(player.basic_data_model.player_basic_info()),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(CreateRoleScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_player_transaction(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetPlayerTransactionCsReq,
|
||||
) -> NetResult<GetPlayerTransactionScRsp> {
|
||||
Ok(GetPlayerTransactionScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
transaction: format!("{}-{}", 1337, 100),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_keep_alive(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_ntf: KeepAliveNotify,
|
||||
) -> NetResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn on_player_logout(
|
||||
session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_ntf: PlayerLogoutNotify,
|
||||
) -> NetResult<()> {
|
||||
tracing::info!(
|
||||
"player logout requested (uid: {})",
|
||||
session.player_uid().unwrap()
|
||||
);
|
||||
Err(NetError::Logout)
|
||||
}
|
12
nap_gameserver/src/handlers/private_message.rs
Normal file
12
nap_gameserver/src/handlers/private_message.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_private_message_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetPrivateMessageDataCsReq,
|
||||
) -> NetResult<GetPrivateMessageDataScRsp> {
|
||||
Ok(GetPrivateMessageDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
private_message_data: Some(PrivateMessageData::default()),
|
||||
})
|
||||
}
|
35
nap_gameserver/src/handlers/quest.rs
Normal file
35
nap_gameserver/src/handlers/quest.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_quest_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: GetQuestDataCsReq,
|
||||
) -> NetResult<GetQuestDataScRsp> {
|
||||
Ok(GetQuestDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
quest_type: req.quest_type,
|
||||
quest_data: Some(QuestData::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_yorozuya_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetYorozuyaInfoCsReq,
|
||||
) -> NetResult<GetYorozuyaInfoScRsp> {
|
||||
Ok(GetYorozuyaInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
yorozuya_info: Some(YorozuyaInfo::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_archive_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetArchiveInfoCsReq,
|
||||
) -> NetResult<GetArchiveInfoScRsp> {
|
||||
Ok(GetArchiveInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
archive_info: Some(ArchiveInfo::default()),
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/ramen.rs
Normal file
12
nap_gameserver/src/handlers/ramen.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_ramen_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetRamenDataCsReq,
|
||||
) -> NetResult<GetRamenDataScRsp> {
|
||||
Ok(GetRamenDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
ramen_data: Some(RamenData::default()),
|
||||
})
|
||||
}
|
12
nap_gameserver/src/handlers/vhs_store.rs
Normal file
12
nap_gameserver/src/handlers/vhs_store.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
pub async fn on_get_vhs_store_info(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: GetVhsStoreInfoCsReq,
|
||||
) -> NetResult<GetVhsStoreInfoScRsp> {
|
||||
Ok(GetVhsStoreInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
info: Some(VhsStoreInfo::default()),
|
||||
})
|
||||
}
|
200
nap_gameserver/src/handlers/world.rs
Normal file
200
nap_gameserver/src/handlers/world.rs
Normal file
|
@ -0,0 +1,200 @@
|
|||
use super::core::NetError;
|
||||
|
||||
use crate::{
|
||||
logic::{game::*, procedure::ProcedureAction, ELocalPlayType},
|
||||
net::NetSessionState,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_enter_world(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: EnterWorldCsReq,
|
||||
) -> NetResult<EnterWorldScRsp> {
|
||||
session.set_state(NetSessionState::EndBasicsReq);
|
||||
|
||||
if player.basic_data_model.beginner_procedure_id != -1 {
|
||||
player.game_instance = GameInstance::Fresh(FreshGame::new(
|
||||
player.basic_data_model.beginner_procedure_id,
|
||||
))
|
||||
} else {
|
||||
player.init_frontend_game()?;
|
||||
}
|
||||
|
||||
let world_init_notify = player.game_instance.create_world_init_notify()?;
|
||||
session.notify(world_init_notify).await?;
|
||||
|
||||
session.set_state(NetSessionState::EnterWorldScRsp);
|
||||
Ok(EnterWorldScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_advance_beginner_procedure(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: AdvanceBeginnerProcedureCsReq,
|
||||
) -> NetResult<AdvanceBeginnerProcedureScRsp> {
|
||||
let is_end = {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.try_complete_procedure(req.procedure_id)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
player.basic_data_model.beginner_procedure_id = fresh_game.procedure_mgr.procedure_id();
|
||||
fresh_game.procedure_mgr.is_end()
|
||||
};
|
||||
|
||||
if is_end {
|
||||
player.init_frontend_game()?;
|
||||
|
||||
let world_init_notify = player.game_instance.create_world_init_notify()?;
|
||||
session.notify(world_init_notify).await?;
|
||||
}
|
||||
|
||||
Ok(AdvanceBeginnerProcedureScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
next_procedure_id: req.procedure_id,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_beginner_battle_begin(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: BeginnerBattleBeginCsReq,
|
||||
) -> NetResult<BeginnerBattleBeginScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::BeginnerBattleBegin)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
Ok(BeginnerBattleBeginScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
battle_uid: req.battle_id as i64,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_beginner_battle_end(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: BeginnerBattleEndCsReq,
|
||||
) -> NetResult<BeginnerBattleEndScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"beginner battle end, id: {}, uid: {}, statistics: {:?}",
|
||||
req.battle_id,
|
||||
req.battle_uid,
|
||||
req.battle_statistics
|
||||
);
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::BeginnerBattleEnd)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
Ok(BeginnerBattleEndScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_beginner_battle_rebegin(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: BeginnerBattleRebeginCsReq,
|
||||
) -> NetResult<BeginnerBattleRebeginScRsp> {
|
||||
Ok(BeginnerBattleRebeginScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_enter_section(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: EnterSectionCsReq,
|
||||
) -> NetResult<EnterSectionScRsp> {
|
||||
Ok(EnterSectionScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_save_pos_in_main_city(
|
||||
_session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: SavePosInMainCityCsReq,
|
||||
) -> NetResult<SavePosInMainCityScRsp> {
|
||||
if let Some(transform) = req.position {
|
||||
player
|
||||
.main_city_model
|
||||
.update_position(transform.position, transform.rotation);
|
||||
}
|
||||
|
||||
Ok(SavePosInMainCityScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_world_init_finish(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: WorldInitFinishCsReq,
|
||||
) -> NetResult<WorldInitFinishScRsp> {
|
||||
Ok(WorldInitFinishScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_start_trial_fighting_mission(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: StartTrialFightingMissionCsReq,
|
||||
) -> NetResult<StartTrialFightingMissionScRsp> {
|
||||
player.game_instance = GameInstance::Hollow(
|
||||
HollowGame::create_training_game(req.quest_id, ELocalPlayType::TrainingRoomFight)
|
||||
.map_err(LogicError::from)?,
|
||||
);
|
||||
|
||||
let world_init_notify = player.game_instance.create_world_init_notify()?;
|
||||
session.notify(world_init_notify).await?;
|
||||
|
||||
Ok(StartTrialFightingMissionScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_end_battle(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: EndBattleCsReq,
|
||||
) -> NetResult<EndBattleScRsp> {
|
||||
Ok(EndBattleScRsp {
|
||||
battle_reward: Some(BattleRewardInfo::default()),
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_leave_cur_dungeon(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
_req: LeaveCurDungeonCsReq,
|
||||
) -> NetResult<LeaveCurDungeonScRsp> {
|
||||
player.init_frontend_game()?;
|
||||
|
||||
let world_init_notify = player.game_instance.create_world_init_notify()?;
|
||||
session.notify(world_init_notify).await?;
|
||||
|
||||
Ok(LeaveCurDungeonScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
144
nap_gameserver/src/logic/enums.rs
Normal file
144
nap_gameserver/src/logic/enums.rs
Normal file
|
@ -0,0 +1,144 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use num_enum::FromPrimitive;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum ESceneType {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
Hall = 1,
|
||||
Hollow = 2,
|
||||
Fight = 3,
|
||||
Fresh = 4,
|
||||
MultiFight = 5,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, FromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum ESystem {
|
||||
#[default]
|
||||
None = 0xFFFFFFFF,
|
||||
VhsStore = 7,
|
||||
Gacha = 21,
|
||||
Hadal = 43,
|
||||
MonsterCard = 40,
|
||||
AbyssCollect = 45,
|
||||
Vhs = 1,
|
||||
ActivityPv = 48,
|
||||
StoryModeSwitch = 12,
|
||||
RamenStore = 8,
|
||||
QteSwitch = 13,
|
||||
DoubleElite = 36,
|
||||
LandRevive = 35,
|
||||
HadalShop = 47,
|
||||
Role = 2,
|
||||
Grocery = 10,
|
||||
AvatarBase = 33,
|
||||
Activity = 27,
|
||||
BuddyInstall = 26,
|
||||
AvatarEquip = 34,
|
||||
TartarusHounds = 20,
|
||||
BossBig = 38,
|
||||
Buddy = 25,
|
||||
Interknot = 6,
|
||||
Workbench = 9,
|
||||
HIA = 39,
|
||||
Smithy = 3,
|
||||
Trash = 23,
|
||||
UseStoryMode = 15,
|
||||
Photowall = 44,
|
||||
AbyssShop = 46,
|
||||
AbyssHeat = 29,
|
||||
DailyQuest = 41,
|
||||
Newsstand = 17,
|
||||
Cafe = 22,
|
||||
Rally = 42,
|
||||
HollowQuest = 0,
|
||||
Package = 4,
|
||||
VideoShop = 11,
|
||||
BattleDaily = 24,
|
||||
Arcade = 19,
|
||||
BossSmall = 37,
|
||||
LineupSelect = 14,
|
||||
ArcadeRoom = 30,
|
||||
Teleport = 5,
|
||||
Train = 32,
|
||||
UseManualQteMode = 16,
|
||||
ArcadeGame = 31,
|
||||
Abyss = 28,
|
||||
Toy = 18,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, FromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum EOperator {
|
||||
Enter = 0,
|
||||
Log = 1,
|
||||
Leave = 2,
|
||||
#[default]
|
||||
Undefined = 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
pub enum TimePeriodType {
|
||||
Morning = 0,
|
||||
Evening = 1,
|
||||
Night = 2,
|
||||
}
|
||||
|
||||
impl Display for TimePeriodType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
pub enum WeatherType {
|
||||
SunShine = 0,
|
||||
Fog = 1,
|
||||
Cloudy = 2,
|
||||
Rain = 3,
|
||||
Thunder = 4,
|
||||
ThickFog = 5,
|
||||
ThickCloudy = 6,
|
||||
#[default]
|
||||
None = 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
impl Display for WeatherType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub enum ELocalPlayType {
|
||||
TrainingRoom = 290,
|
||||
BigBossBattle = 211,
|
||||
BossLittleBattleLongfight = 215,
|
||||
PureHollowBattle = 280,
|
||||
DualElite = 208,
|
||||
PureHollowBattleHardmode = 282,
|
||||
OperationBetaDemo = 216,
|
||||
AvatarDemoTrial = 213,
|
||||
BossRushBattle = 218,
|
||||
BossBattle = 210,
|
||||
GuideSpecial = 203,
|
||||
DailyChallenge = 206,
|
||||
OperationTeamCoop = 219,
|
||||
TrainingRoomFight = 291,
|
||||
LevelZero = 205,
|
||||
ArchiveLongFight = 212,
|
||||
MpBigBossBattle = 214,
|
||||
RallyLongFight = 207,
|
||||
BigBossBattleLongfight = 217,
|
||||
ArchiveBattle = 201,
|
||||
PureHollowBattleLonghfight = 281,
|
||||
HadalZone = 209,
|
||||
ChessBoardBattle = 202,
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
}
|
37
nap_gameserver/src/logic/game/fresh.rs
Normal file
37
nap_gameserver/src/logic/game/fresh.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use proto::{DungeonInfo, FreshSceneInfo, SceneInfo};
|
||||
|
||||
use crate::logic::{procedure::ProcedureManager, ESceneType};
|
||||
|
||||
use super::NapGameMode;
|
||||
|
||||
pub struct FreshGame {
|
||||
pub procedure_mgr: ProcedureManager,
|
||||
}
|
||||
|
||||
impl FreshGame {
|
||||
pub fn new(start_procedure_id: i32) -> Self {
|
||||
Self {
|
||||
procedure_mgr: ProcedureManager::new(start_procedure_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NapGameMode for FreshGame {
|
||||
fn scene_type(&self) -> ESceneType {
|
||||
ESceneType::Fresh
|
||||
}
|
||||
|
||||
fn scene_info(&self) -> Option<SceneInfo> {
|
||||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
fresh_scene_info: Some(FreshSceneInfo {
|
||||
beginner_procedure_id: (self.procedure_mgr.procedure_id() - 1) as u32,
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn dungeon_info(&self) -> Option<DungeonInfo> {
|
||||
None
|
||||
}
|
||||
}
|
90
nap_gameserver/src/logic/game/frontend.rs
Normal file
90
nap_gameserver/src/logic/game/frontend.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use data::tables;
|
||||
use proto::*;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::logic::{math::Vector3f, time::MainCityTime, ESceneType};
|
||||
|
||||
use super::NapGameMode;
|
||||
|
||||
pub struct FrontendGame {
|
||||
section_id: u32,
|
||||
frontend_avatar_id: i32,
|
||||
camera_x: u32,
|
||||
camera_y: u32,
|
||||
born_pos: String,
|
||||
main_city_time: MainCityTime,
|
||||
avatar_pos: Vector3f,
|
||||
avatar_rot: Vector3f,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FrontendGameError {
|
||||
#[error("section id is invalid ({0})")]
|
||||
InvalidSection(u32),
|
||||
}
|
||||
|
||||
impl FrontendGame {
|
||||
pub fn new(
|
||||
section_id: u32,
|
||||
avatar_id: i32,
|
||||
main_city_time: MainCityTime,
|
||||
avatar_pos: Vector3f,
|
||||
avatar_rot: Vector3f,
|
||||
) -> Result<Self, FrontendGameError> {
|
||||
let instance = Self {
|
||||
section_id,
|
||||
main_city_time,
|
||||
frontend_avatar_id: avatar_id,
|
||||
camera_x: 0xFFFFFFFF,
|
||||
camera_y: 0xFFFFFFFF,
|
||||
born_pos: Self::get_default_stage_entry_name(section_id)
|
||||
.ok_or(FrontendGameError::InvalidSection(section_id))?,
|
||||
avatar_pos,
|
||||
avatar_rot,
|
||||
};
|
||||
|
||||
tracing::info!("creating new frontend game (section={section_id}, avatar={avatar_id})");
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
fn get_default_stage_entry_name(section_id: u32) -> Option<String> {
|
||||
tables::section_config_template_tb::iter()
|
||||
.find(|tmpl| tmpl.section_id == section_id)
|
||||
.map(|tmpl| tmpl.primary_entry_name.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl NapGameMode for FrontendGame {
|
||||
fn scene_info(&self) -> Option<SceneInfo> {
|
||||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
hall_scene_info: Some(HallSceneInfo {
|
||||
section_id: self.section_id,
|
||||
frontend_avatar_id: self.frontend_avatar_id as u32,
|
||||
camera_x: self.camera_x,
|
||||
camera_y: self.camera_y,
|
||||
born_pos: self
|
||||
.avatar_pos
|
||||
.is_zero()
|
||||
.then_some(self.born_pos.clone())
|
||||
.unwrap_or_default(),
|
||||
day_of_week: self.main_city_time.day_of_week.value(),
|
||||
time_of_day: self.main_city_time.time_of_day.value(),
|
||||
position: (!self.avatar_pos.is_zero()).then_some(Transform {
|
||||
position: self.avatar_pos.to_vec(),
|
||||
rotation: self.avatar_rot.to_vec(),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn dungeon_info(&self) -> Option<DungeonInfo> {
|
||||
None
|
||||
}
|
||||
|
||||
fn scene_type(&self) -> ESceneType {
|
||||
ESceneType::Hall
|
||||
}
|
||||
}
|
75
nap_gameserver/src/logic/game/hollow.rs
Normal file
75
nap_gameserver/src/logic/game/hollow.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use common::util;
|
||||
use data::tables;
|
||||
use proto::{DungeonInfo, DungeonItemData, FightSceneInfo, SceneInfo, WeatherPoolInfo};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::logic::{ELocalPlayType, ESceneType, TimePeriodType, WeatherType};
|
||||
|
||||
use super::NapGameMode;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum HollowGameError {
|
||||
#[error("quest id is invalid: {0}")]
|
||||
InvalidQuestId(u32),
|
||||
}
|
||||
|
||||
pub struct HollowGame {
|
||||
pub quest_id: u32,
|
||||
pub battle_event_id: u32,
|
||||
pub time_period: TimePeriodType,
|
||||
pub weather: WeatherType,
|
||||
pub play_type: ELocalPlayType,
|
||||
pub start_timestamp: i64,
|
||||
}
|
||||
|
||||
impl HollowGame {
|
||||
pub fn create_training_game(
|
||||
training_quest_id: u32,
|
||||
play_type: ELocalPlayType,
|
||||
) -> Result<Self, HollowGameError> {
|
||||
let template = tables::training_quest_template_tb::iter()
|
||||
.find(|tmpl| tmpl.id == training_quest_id)
|
||||
.ok_or(HollowGameError::InvalidQuestId(training_quest_id))?;
|
||||
|
||||
Ok(Self {
|
||||
quest_id: template.id,
|
||||
battle_event_id: template.battle_event_id,
|
||||
time_period: TimePeriodType::Morning,
|
||||
weather: WeatherType::SunShine,
|
||||
start_timestamp: util::cur_timestamp() as i64,
|
||||
play_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl NapGameMode for HollowGame {
|
||||
fn scene_type(&self) -> ESceneType {
|
||||
ESceneType::Fight
|
||||
}
|
||||
|
||||
fn scene_info(&self) -> Option<SceneInfo> {
|
||||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
battle_event_id: self.battle_event_id,
|
||||
play_type: self.play_type as u32,
|
||||
fight_scene_info: Some(FightSceneInfo {
|
||||
weather_pool: Some(WeatherPoolInfo {
|
||||
time_period: self.time_period.to_string(),
|
||||
weather: self.weather.to_string(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn dungeon_info(&self) -> Option<DungeonInfo> {
|
||||
Some(DungeonInfo {
|
||||
quest_id: self.quest_id,
|
||||
start_timestamp: self.start_timestamp,
|
||||
dungeon_item_data: Some(DungeonItemData::default()),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
60
nap_gameserver/src/logic/game/mod.rs
Normal file
60
nap_gameserver/src/logic/game/mod.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
mod fresh;
|
||||
mod frontend;
|
||||
mod hollow;
|
||||
pub use fresh::*;
|
||||
pub use frontend::*;
|
||||
pub use hollow::*;
|
||||
|
||||
use proto::{DungeonInfo, SceneInfo, WorldInitScNotify};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::{procedure::ProcedureError, ESceneType};
|
||||
|
||||
#[derive(Default)]
|
||||
pub enum GameInstance {
|
||||
Frontend(FrontendGame),
|
||||
Fresh(FreshGame),
|
||||
Hollow(HollowGame),
|
||||
#[default]
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum LogicError {
|
||||
#[error("game instance is NULL!")]
|
||||
GameIsNull,
|
||||
#[error("frontend error: {0}")]
|
||||
Frontend(#[from] FrontendGameError),
|
||||
#[error("procedure error: {0}")]
|
||||
Procedure(#[from] ProcedureError),
|
||||
#[error("hollow error: {0}")]
|
||||
Hollow(#[from] HollowGameError),
|
||||
}
|
||||
|
||||
impl GameInstance {
|
||||
pub fn is_null(&self) -> bool {
|
||||
matches!(self, Self::Null)
|
||||
}
|
||||
|
||||
pub fn create_world_init_notify(&self) -> Result<WorldInitScNotify, LogicError> {
|
||||
Ok(Self::world_init_sc_notify(match self {
|
||||
Self::Frontend(game) => game,
|
||||
Self::Fresh(game) => game,
|
||||
Self::Hollow(game) => game,
|
||||
Self::Null => return Err(LogicError::GameIsNull),
|
||||
}))
|
||||
}
|
||||
|
||||
fn world_init_sc_notify(game: &dyn NapGameMode) -> WorldInitScNotify {
|
||||
WorldInitScNotify {
|
||||
scene_info: game.scene_info(),
|
||||
dungeon_info: game.dungeon_info(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NapGameMode {
|
||||
fn scene_type(&self) -> ESceneType;
|
||||
fn scene_info(&self) -> Option<SceneInfo>;
|
||||
fn dungeon_info(&self) -> Option<DungeonInfo>;
|
||||
}
|
47
nap_gameserver/src/logic/item/item_model.rs
Normal file
47
nap_gameserver/src/logic/item/item_model.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use super::ResourceItem;
|
||||
use proto::ItemModelBin;
|
||||
|
||||
pub struct ItemModel {
|
||||
pub resources: Vec<ResourceItem>,
|
||||
}
|
||||
|
||||
impl ItemModel {
|
||||
pub fn from_bin(bin: ItemModelBin) -> Self {
|
||||
Self {
|
||||
resources: bin
|
||||
.resource_list
|
||||
.into_iter()
|
||||
.map(ResourceItem::from_bin)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> ItemModelBin {
|
||||
ItemModelBin {
|
||||
resource_list: self.resources.iter().map(ResourceItem::to_bin).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_resource(&mut self, template_id: u32, num: u32) {
|
||||
if let Some(item) = self
|
||||
.resources
|
||||
.iter_mut()
|
||||
.find(|item| item.template_id == template_id)
|
||||
{
|
||||
item.num += num as i32;
|
||||
} else {
|
||||
self.resources.push(ResourceItem {
|
||||
template_id,
|
||||
num: num as i32,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ItemModel {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
resources: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
5
nap_gameserver/src/logic/item/mod.rs
Normal file
5
nap_gameserver/src/logic/item/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod item_model;
|
||||
mod resource;
|
||||
|
||||
pub use item_model::ItemModel;
|
||||
pub use resource::ResourceItem;
|
29
nap_gameserver/src/logic/item/resource.rs
Normal file
29
nap_gameserver/src/logic/item/resource.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use proto::{Resource, ResourceItemBin};
|
||||
|
||||
pub struct ResourceItem {
|
||||
pub template_id: u32,
|
||||
pub num: i32,
|
||||
}
|
||||
|
||||
impl ResourceItem {
|
||||
pub fn from_bin(bin: ResourceItemBin) -> Self {
|
||||
Self {
|
||||
template_id: bin.template_id,
|
||||
num: bin.num,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> ResourceItemBin {
|
||||
ResourceItemBin {
|
||||
template_id: self.template_id,
|
||||
num: self.num,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> Resource {
|
||||
Resource {
|
||||
template_id: self.template_id,
|
||||
num: self.num,
|
||||
}
|
||||
}
|
||||
}
|
24
nap_gameserver/src/logic/math.rs
Normal file
24
nap_gameserver/src/logic/math.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
#[derive(Default, Clone, Debug)]
|
||||
pub struct Vector3f {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
}
|
||||
|
||||
impl Vector3f {
|
||||
pub fn from_vec(v: Vec<f64>) -> Self {
|
||||
Self {
|
||||
x: v.get(0).cloned().unwrap_or_default(),
|
||||
y: v.get(1).cloned().unwrap_or_default(),
|
||||
z: v.get(2).cloned().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<f64> {
|
||||
vec![self.x, self.y, self.z]
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.x == 0.0 && self.y == 0.0 && self.z == 0.0
|
||||
}
|
||||
}
|
11
nap_gameserver/src/logic/mod.rs
Normal file
11
nap_gameserver/src/logic/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
mod enums;
|
||||
pub mod game;
|
||||
pub mod item;
|
||||
pub mod math;
|
||||
pub mod player;
|
||||
pub mod procedure;
|
||||
pub mod role;
|
||||
pub mod time;
|
||||
|
||||
pub use enums::*;
|
||||
pub use player::Player;
|
62
nap_gameserver/src/logic/player/basic_data_model.rs
Normal file
62
nap_gameserver/src/logic/player/basic_data_model.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use proto::{BasicDataModelBin, PlayerBasicInfo};
|
||||
|
||||
pub struct BasicDataModel {
|
||||
pub level: u32,
|
||||
pub exp: u32,
|
||||
pub profile_icon: u32,
|
||||
pub nick_name: Option<String>,
|
||||
pub frontend_avatar_id: i32,
|
||||
pub beginner_procedure_id: i32,
|
||||
}
|
||||
|
||||
impl Default for BasicDataModel {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
level: 1,
|
||||
exp: 0,
|
||||
profile_icon: 3200000,
|
||||
nick_name: None,
|
||||
frontend_avatar_id: 0,
|
||||
beginner_procedure_id: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BasicDataModel {
|
||||
pub fn player_basic_info(&self) -> PlayerBasicInfo {
|
||||
PlayerBasicInfo {
|
||||
nick_name: self.nick_name.clone().unwrap_or_default(),
|
||||
exp: self.exp,
|
||||
level: self.level,
|
||||
avatar_id: self.frontend_avatar_id as u32,
|
||||
frontend_avatar_id: self.frontend_avatar_id as u32,
|
||||
kbjleelonfe: self.profile_icon,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bin(bin: BasicDataModelBin) -> Self {
|
||||
Self {
|
||||
level: bin.level,
|
||||
exp: bin.exp,
|
||||
profile_icon: bin.profile_icon,
|
||||
frontend_avatar_id: bin.frontend_avatar_id,
|
||||
beginner_procedure_id: bin.beginner_procedure_id,
|
||||
nick_name: match bin.nick_name.is_empty() {
|
||||
true => None,
|
||||
false => Some(bin.nick_name),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> BasicDataModelBin {
|
||||
BasicDataModelBin {
|
||||
level: self.level,
|
||||
exp: self.exp,
|
||||
profile_icon: self.profile_icon,
|
||||
frontend_avatar_id: self.frontend_avatar_id,
|
||||
nick_name: self.nick_name.clone().unwrap_or_default(),
|
||||
beginner_procedure_id: self.beginner_procedure_id,
|
||||
}
|
||||
}
|
||||
}
|
37
nap_gameserver/src/logic/player/lock_model.rs
Normal file
37
nap_gameserver/src/logic/player/lock_model.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use proto::{LockModelBin, UnlockData};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LockModel {
|
||||
unlock_list: BTreeSet<i32>,
|
||||
}
|
||||
|
||||
impl LockModel {
|
||||
pub fn from_bin(bin: LockModelBin) -> Self {
|
||||
Self {
|
||||
unlock_list: bin.unlock_list.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> LockModelBin {
|
||||
LockModelBin {
|
||||
unlock_list: self.unlock_list.clone().into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> UnlockData {
|
||||
UnlockData {
|
||||
unlock_id_list: self.unlock_list.clone().into_iter().collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_unlock(&mut self, id: i32) {
|
||||
self.unlock_list.insert(id);
|
||||
}
|
||||
|
||||
pub fn is_unlock(&self, id: i32) -> bool {
|
||||
self.unlock_list.contains(&id)
|
||||
}
|
||||
}
|
50
nap_gameserver/src/logic/player/main_city_model.rs
Normal file
50
nap_gameserver/src/logic/player/main_city_model.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use proto::{MainCityModelBin, TransformBin};
|
||||
|
||||
use super::{math::Vector3f, time::MainCityTime};
|
||||
|
||||
pub struct MainCityModel {
|
||||
pub position: Vector3f,
|
||||
pub rotation: Vector3f,
|
||||
pub main_city_time: MainCityTime,
|
||||
pub section_id: u32,
|
||||
}
|
||||
|
||||
impl MainCityModel {
|
||||
pub fn update_position(&mut self, pos: Vec<f64>, rot: Vec<f64>) {
|
||||
self.position = Vector3f::from_vec(pos);
|
||||
self.rotation = Vector3f::from_vec(rot);
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> MainCityModelBin {
|
||||
MainCityModelBin {
|
||||
transform: Some(TransformBin {
|
||||
position: self.position.to_vec(),
|
||||
rotation: self.position.to_vec(),
|
||||
}),
|
||||
time: Some(self.main_city_time.to_bin()),
|
||||
section_id: self.section_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bin(bin: MainCityModelBin) -> Self {
|
||||
let transform = bin.transform.unwrap_or_default();
|
||||
|
||||
Self {
|
||||
position: Vector3f::from_vec(transform.position),
|
||||
rotation: Vector3f::from_vec(transform.rotation),
|
||||
main_city_time: bin.time.map(MainCityTime::from_bin).unwrap_or_default(),
|
||||
section_id: bin.section_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MainCityModel {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
position: Vector3f::default(),
|
||||
rotation: Vector3f::default(),
|
||||
main_city_time: MainCityTime::default(),
|
||||
section_id: 1,
|
||||
}
|
||||
}
|
||||
}
|
12
nap_gameserver/src/logic/player/mod.rs
Normal file
12
nap_gameserver/src/logic/player/mod.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::*;
|
||||
|
||||
mod basic_data_model;
|
||||
mod lock_model;
|
||||
mod main_city_model;
|
||||
mod player;
|
||||
mod player_mgr;
|
||||
|
||||
pub use basic_data_model::BasicDataModel;
|
||||
pub use lock_model::LockModel;
|
||||
pub use player::Player;
|
||||
pub use player_mgr::PlayerManager;
|
100
nap_gameserver/src/logic/player/player.rs
Normal file
100
nap_gameserver/src/logic/player/player.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
use data::tables;
|
||||
use proto::{ItemStatic, PlayerDataBin, Retcode};
|
||||
|
||||
use super::game::{FrontendGame, GameInstance, LogicError};
|
||||
use super::item::ItemModel;
|
||||
use super::main_city_model::MainCityModel;
|
||||
use super::role::RoleModel;
|
||||
use super::{BasicDataModel, LockModel};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Player {
|
||||
current_session_id: Option<u64>,
|
||||
pub game_instance: GameInstance,
|
||||
pub basic_data_model: BasicDataModel,
|
||||
pub lock_model: LockModel,
|
||||
pub role_model: RoleModel,
|
||||
pub item_model: ItemModel,
|
||||
pub main_city_model: MainCityModel,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
const MAIN_AVATAR_IDS: [i32; 2] = [2011, 2021];
|
||||
|
||||
pub fn save_to_bin(&self) -> PlayerDataBin {
|
||||
PlayerDataBin {
|
||||
basic_data_model: Some(self.basic_data_model.to_bin()),
|
||||
lock_model: Some(self.lock_model.to_bin()),
|
||||
role_model: Some(self.role_model.to_bin()),
|
||||
item_model: Some(self.item_model.to_bin()),
|
||||
main_city_model: Some(self.main_city_model.to_bin()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_from_bin(bin: PlayerDataBin) -> Self {
|
||||
Self {
|
||||
basic_data_model: bin
|
||||
.basic_data_model
|
||||
.map(BasicDataModel::from_bin)
|
||||
.unwrap_or_default(),
|
||||
lock_model: bin.lock_model.map(LockModel::from_bin).unwrap_or_default(),
|
||||
role_model: bin.role_model.map(RoleModel::from_bin).unwrap_or_default(),
|
||||
item_model: bin.item_model.map(ItemModel::from_bin).unwrap_or_default(),
|
||||
main_city_model: bin
|
||||
.main_city_model
|
||||
.map(MainCityModel::from_bin)
|
||||
.unwrap_or_default(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_login(&mut self) {
|
||||
tables::unlock_config_template_tb::iter()
|
||||
.for_each(|tmpl| self.lock_model.add_unlock(tmpl.id))
|
||||
}
|
||||
|
||||
pub fn on_first_login(&mut self) {
|
||||
self.item_model
|
||||
.add_resource(ItemStatic::FrontendGold as u32, 1_000_000);
|
||||
self.item_model
|
||||
.add_resource(ItemStatic::GameDiamond as u32, 1_000_000);
|
||||
self.item_model.add_resource(ItemStatic::Energy as u32, 240);
|
||||
}
|
||||
|
||||
pub fn init_frontend_game(&mut self) -> Result<(), LogicError> {
|
||||
let main_city = &self.main_city_model;
|
||||
self.game_instance = GameInstance::Frontend(
|
||||
FrontendGame::new(
|
||||
main_city.section_id,
|
||||
self.basic_data_model.frontend_avatar_id,
|
||||
main_city.main_city_time.clone(),
|
||||
main_city.position.clone(),
|
||||
main_city.rotation.clone(),
|
||||
)
|
||||
.map_err(LogicError::from)?,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_frontend_avatar(&mut self, id: i32) -> Result<(), Retcode> {
|
||||
(self.basic_data_model.frontend_avatar_id == 0)
|
||||
.then_some(())
|
||||
.ok_or(Retcode::RetFail)?;
|
||||
|
||||
(Self::MAIN_AVATAR_IDS.contains(&id))
|
||||
.then_some(())
|
||||
.ok_or(Retcode::RetFail)?;
|
||||
|
||||
self.basic_data_model.frontend_avatar_id = id;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_current_session(&mut self, id: u64) {
|
||||
self.current_session_id = Some(id);
|
||||
}
|
||||
|
||||
pub fn current_session_id(&self) -> Option<u64> {
|
||||
self.current_session_id
|
||||
}
|
||||
}
|
142
nap_gameserver/src/logic/player/player_mgr.rs
Normal file
142
nap_gameserver/src/logic/player/player_mgr.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use prost::Message;
|
||||
use proto::{PlayerDataBin, Retcode};
|
||||
use sqlx::PgPool;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::database::{self, DbError};
|
||||
|
||||
use super::Player;
|
||||
|
||||
pub type SharedPlayerLock = Arc<Mutex<Player>>;
|
||||
|
||||
pub struct PlayerManager {
|
||||
players: DashMap<u32, SharedPlayerLock>,
|
||||
pg_pool: PgPool,
|
||||
}
|
||||
|
||||
impl PlayerManager {
|
||||
pub fn new(pg_pool: PgPool) -> Self {
|
||||
Self {
|
||||
players: DashMap::new(),
|
||||
pg_pool,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn authorize(
|
||||
&self,
|
||||
account_uid: &str,
|
||||
token: &str,
|
||||
platform_type: u32,
|
||||
) -> Result<u32, Retcode> {
|
||||
let combo_token =
|
||||
match database::select_combo_token_by_account(&self.pg_pool, account_uid).await {
|
||||
Ok(row) => row.token,
|
||||
Err(_) => return Err(Retcode::RetFail),
|
||||
};
|
||||
|
||||
(combo_token == token)
|
||||
.then_some(())
|
||||
.ok_or(Retcode::RetFail)?;
|
||||
|
||||
let player_uid = match database::select_player_uid_by_account(&self.pg_pool, account_uid)
|
||||
.await
|
||||
{
|
||||
Ok(row) => row.uid,
|
||||
Err(DbError::NotFound) => {
|
||||
database::insert_player_uid_by_account(&self.pg_pool, account_uid, platform_type)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
tracing::error!("failed to insert player_uid: {err}");
|
||||
Retcode::RetFail
|
||||
})?
|
||||
.uid
|
||||
}
|
||||
Err(_) => return Err(Retcode::RetFail),
|
||||
} as u32;
|
||||
|
||||
Ok(player_uid)
|
||||
}
|
||||
|
||||
pub async fn get_player(&self, uid: u32) -> Option<SharedPlayerLock> {
|
||||
if let Some(player) = self.players.get(&uid).map(|a| (*a).clone()) {
|
||||
return Some(player);
|
||||
}
|
||||
|
||||
let player_bin_data =
|
||||
match database::select_player_data_by_uid(&self.pg_pool, uid as i32).await {
|
||||
Ok(row) => Some(row.bin_data),
|
||||
Err(DbError::NotFound) => None,
|
||||
Err(DbError::SqlxError(err)) => {
|
||||
tracing::error!("SQL error: {err}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let player = match player_bin_data {
|
||||
Some(bin_data) => match PlayerDataBin::decode(&*bin_data) {
|
||||
Ok(bin) => Player::load_from_bin(bin),
|
||||
Err(err) => {
|
||||
tracing::error!("failed to decode PlayerDataBin for uid {uid}, error: {err}");
|
||||
return None;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let mut player = Player::default();
|
||||
player.on_first_login();
|
||||
|
||||
match database::insert_player_data_by_uid(
|
||||
&self.pg_pool,
|
||||
uid as i32,
|
||||
player.save_to_bin().encode_to_vec(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => player,
|
||||
Err(err) => {
|
||||
tracing::error!("failed to insert player data, uid: {uid}, error: {err}");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.players.insert(uid, Arc::new(Mutex::new(player)));
|
||||
self.players.get(&uid).map(|a| (*a).clone())
|
||||
}
|
||||
|
||||
pub async fn save(&self, player_uid: u32) {
|
||||
let Some(player_lock) = self.players.get(&player_uid) else {
|
||||
tracing::warn!("save: player with uid {player_uid} not found");
|
||||
return;
|
||||
};
|
||||
|
||||
let player = player_lock.lock().await;
|
||||
self.do_save(player_uid, &*player).await;
|
||||
}
|
||||
|
||||
pub async fn save_and_remove(&self, player_uid: u32) {
|
||||
let Some((_, player_lock)) = self.players.remove(&player_uid) else {
|
||||
tracing::warn!("save_and_remove: player with uid {player_uid} not found");
|
||||
return;
|
||||
};
|
||||
|
||||
let player = player_lock.lock().await;
|
||||
self.do_save(player_uid, &*player).await;
|
||||
}
|
||||
|
||||
async fn do_save(&self, uid: u32, player: &Player) {
|
||||
let bin = player.save_to_bin();
|
||||
|
||||
if let Err(err) =
|
||||
database::update_player_data_by_uid(&self.pg_pool, uid as i32, bin.encode_to_vec())
|
||||
.await
|
||||
{
|
||||
tracing::error!("failed to update player data: {err}");
|
||||
}
|
||||
|
||||
tracing::info!("player data flushed to database, uid: {uid}");
|
||||
}
|
||||
}
|
58
nap_gameserver/src/logic/procedure/battle.rs
Normal file
58
nap_gameserver/src/logic/procedure/battle.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use super::{ProcedureAction, ProcedureBase, ProcedureError, ProcedureState, ProcedureType};
|
||||
|
||||
pub struct ProcedureBattle {
|
||||
id: i32,
|
||||
state: ProcedureState,
|
||||
}
|
||||
|
||||
impl ProcedureBattle {
|
||||
pub fn new(id: i32) -> Self {
|
||||
Self {
|
||||
id,
|
||||
state: ProcedureState::Init,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcedureBase for ProcedureBattle {
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn procedure_type(&self) -> ProcedureType {
|
||||
ProcedureType::Battle
|
||||
}
|
||||
|
||||
fn on_action(&mut self, action: ProcedureAction) -> Result<ProcedureState, ProcedureError> {
|
||||
match action {
|
||||
ProcedureAction::BeginnerBattleBegin => {
|
||||
(self.state == ProcedureState::Init)
|
||||
.then_some(())
|
||||
.ok_or(ProcedureError::InvalidState(action, self.state))?;
|
||||
|
||||
self.state = ProcedureState::Running;
|
||||
}
|
||||
ProcedureAction::BeginnerBattleEnd => {
|
||||
(self.state == ProcedureState::Running)
|
||||
.then_some(())
|
||||
.ok_or(ProcedureError::InvalidState(action, self.state))?;
|
||||
|
||||
self.state = ProcedureState::Finish;
|
||||
}
|
||||
ProcedureAction::PerformTrigger => (),
|
||||
ProcedureAction::PerformEnd => (),
|
||||
_ => {
|
||||
return Err(ProcedureError::UnsupportedAction(
|
||||
action,
|
||||
self.procedure_type(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.state)
|
||||
}
|
||||
|
||||
fn is_finished(&self) -> bool {
|
||||
self.state == ProcedureState::Finish
|
||||
}
|
||||
}
|
102
nap_gameserver/src/logic/procedure/mod.rs
Normal file
102
nap_gameserver/src/logic/procedure/mod.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
mod battle;
|
||||
mod plot_play;
|
||||
mod procedure_mgr;
|
||||
mod select_role;
|
||||
|
||||
pub use battle::ProcedureBattle;
|
||||
pub use plot_play::ProcedurePlotPlay;
|
||||
pub use procedure_mgr::ProcedureManager;
|
||||
pub use select_role::ProcedureSelectRole;
|
||||
|
||||
use data::tables::{self, ProcedureConfigTemplate};
|
||||
use num_enum::TryFromPrimitive;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub enum ProcedureState {
|
||||
Init,
|
||||
Running,
|
||||
Finish,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum ProcedureType {
|
||||
Battle = 1,
|
||||
PlotPlay = 2,
|
||||
SelectRole = 4,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum ProcedureAction {
|
||||
PerformTrigger,
|
||||
PerformEnd,
|
||||
SelectRole,
|
||||
BeginnerBattleBegin,
|
||||
BeginnerBattleEnd,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ProcedureError {
|
||||
#[error("action {0:?} is not allowed for procedure of type {1:?}")]
|
||||
UnsupportedAction(ProcedureAction, ProcedureType),
|
||||
#[error("action {0:?} is not allowed in current state: {1:?}")]
|
||||
InvalidState(ProcedureAction, ProcedureState),
|
||||
#[error("can't advance procedure because it's not finished")]
|
||||
NotFinished,
|
||||
#[error("trying to complete procedure: {0}, current procedure: {1}")]
|
||||
InvalidProcedureId(i32, i32),
|
||||
#[error("current procedure is NULL!")]
|
||||
ProcedureIsNull,
|
||||
}
|
||||
|
||||
pub trait ProcedureBase {
|
||||
fn id(&self) -> i32;
|
||||
fn procedure_type(&self) -> ProcedureType;
|
||||
|
||||
fn get_next_id(&self) -> Option<&i32> {
|
||||
let config = tables::procedure_config_template_tb::iter()
|
||||
.find(|tmpl| tmpl.procedure_id == self.id())
|
||||
.unwrap();
|
||||
|
||||
config.jump_tos.iter().next()
|
||||
}
|
||||
|
||||
fn on_action(&mut self, action: ProcedureAction) -> Result<ProcedureState, ProcedureError>;
|
||||
fn is_finished(&self) -> bool;
|
||||
}
|
||||
|
||||
pub enum Procedure {
|
||||
Battle(ProcedureBattle),
|
||||
PlotPlay(ProcedurePlotPlay),
|
||||
SelectRole(ProcedureSelectRole),
|
||||
}
|
||||
|
||||
impl Procedure {
|
||||
pub fn new(template: &ProcedureConfigTemplate) -> Self {
|
||||
use ProcedureType::*;
|
||||
let procedure_type = ProcedureType::try_from_primitive(template.procedure_type).unwrap();
|
||||
|
||||
match procedure_type {
|
||||
Battle => Procedure::Battle(ProcedureBattle::new(template.procedure_id)),
|
||||
PlotPlay => Procedure::PlotPlay(ProcedurePlotPlay::new(template.procedure_id)),
|
||||
SelectRole => Procedure::SelectRole(ProcedureSelectRole::new(template.procedure_id)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base(&self) -> &dyn ProcedureBase {
|
||||
match self {
|
||||
Self::Battle(proc) => proc,
|
||||
Self::PlotPlay(proc) => proc,
|
||||
Self::SelectRole(proc) => proc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_mut(&mut self) -> &mut dyn ProcedureBase {
|
||||
match self {
|
||||
Self::Battle(proc) => proc,
|
||||
Self::PlotPlay(proc) => proc,
|
||||
Self::SelectRole(proc) => proc,
|
||||
}
|
||||
}
|
||||
}
|
56
nap_gameserver/src/logic/procedure/plot_play.rs
Normal file
56
nap_gameserver/src/logic/procedure/plot_play.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use super::{ProcedureAction, ProcedureBase, ProcedureError, ProcedureState, ProcedureType};
|
||||
|
||||
pub struct ProcedurePlotPlay {
|
||||
id: i32,
|
||||
state: ProcedureState,
|
||||
}
|
||||
|
||||
impl ProcedurePlotPlay {
|
||||
pub fn new(id: i32) -> Self {
|
||||
Self {
|
||||
id,
|
||||
state: ProcedureState::Init,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcedureBase for ProcedurePlotPlay {
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn procedure_type(&self) -> ProcedureType {
|
||||
ProcedureType::PlotPlay
|
||||
}
|
||||
|
||||
fn on_action(&mut self, action: ProcedureAction) -> Result<ProcedureState, ProcedureError> {
|
||||
match action {
|
||||
ProcedureAction::PerformTrigger => {
|
||||
(self.state == ProcedureState::Init)
|
||||
.then_some(())
|
||||
.ok_or(ProcedureError::InvalidState(action, self.state))?;
|
||||
|
||||
self.state = ProcedureState::Running;
|
||||
}
|
||||
ProcedureAction::PerformEnd => {
|
||||
(self.state == ProcedureState::Running)
|
||||
.then_some(())
|
||||
.ok_or(ProcedureError::InvalidState(action, self.state))?;
|
||||
|
||||
self.state = ProcedureState::Finish
|
||||
}
|
||||
_ => {
|
||||
return Err(ProcedureError::UnsupportedAction(
|
||||
action,
|
||||
self.procedure_type(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.state)
|
||||
}
|
||||
|
||||
fn is_finished(&self) -> bool {
|
||||
self.state >= ProcedureState::Running
|
||||
}
|
||||
}
|
66
nap_gameserver/src/logic/procedure/procedure_mgr.rs
Normal file
66
nap_gameserver/src/logic/procedure/procedure_mgr.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use data::tables;
|
||||
|
||||
use super::{Procedure, ProcedureAction, ProcedureError};
|
||||
|
||||
pub struct ProcedureManager {
|
||||
cur_procedure_id: i32,
|
||||
procedures: Vec<Procedure>,
|
||||
}
|
||||
|
||||
impl ProcedureManager {
|
||||
pub fn new(start_procedure_id: i32) -> Self {
|
||||
Self {
|
||||
cur_procedure_id: start_procedure_id,
|
||||
procedures: tables::procedure_config_template_tb::iter()
|
||||
.filter(|tmpl| tmpl.procedure_id >= start_procedure_id)
|
||||
.map(Procedure::new)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_complete_procedure(&mut self, procedure_id: i32) -> Result<(), ProcedureError> {
|
||||
(self.cur_procedure_id == procedure_id)
|
||||
.then_some(())
|
||||
.ok_or(ProcedureError::InvalidProcedureId(
|
||||
procedure_id,
|
||||
self.cur_procedure_id,
|
||||
))?;
|
||||
|
||||
let procedure = self
|
||||
.procedures
|
||||
.iter()
|
||||
.find(|proc| proc.base().id() == procedure_id)
|
||||
.ok_or(ProcedureError::ProcedureIsNull)?;
|
||||
|
||||
if procedure.base().is_finished() {
|
||||
self.cur_procedure_id = procedure.base().get_next_id().cloned().unwrap_or(-1);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ProcedureError::NotFinished)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_action(&mut self, action: ProcedureAction) -> Result<(), ProcedureError> {
|
||||
let procedure = self
|
||||
.procedures
|
||||
.iter_mut()
|
||||
.find(|proc| proc.base().id() == self.cur_procedure_id)
|
||||
.ok_or(ProcedureError::ProcedureIsNull)?;
|
||||
|
||||
let state = procedure.base_mut().on_action(action)?;
|
||||
tracing::info!(
|
||||
"procedure action {action:?} performed, state: {state:?}, procedure id: {}",
|
||||
self.cur_procedure_id
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn procedure_id(&self) -> i32 {
|
||||
self.cur_procedure_id
|
||||
}
|
||||
|
||||
pub fn is_end(&self) -> bool {
|
||||
self.cur_procedure_id == -1
|
||||
}
|
||||
}
|
51
nap_gameserver/src/logic/procedure/select_role.rs
Normal file
51
nap_gameserver/src/logic/procedure/select_role.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use super::{ProcedureAction, ProcedureBase, ProcedureError, ProcedureState, ProcedureType};
|
||||
|
||||
pub struct ProcedureSelectRole {
|
||||
id: i32,
|
||||
state: ProcedureState,
|
||||
}
|
||||
|
||||
impl ProcedureSelectRole {
|
||||
pub fn new(id: i32) -> Self {
|
||||
Self {
|
||||
id,
|
||||
state: ProcedureState::Init,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcedureBase for ProcedureSelectRole {
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn procedure_type(&self) -> ProcedureType {
|
||||
ProcedureType::SelectRole
|
||||
}
|
||||
|
||||
fn on_action(&mut self, action: ProcedureAction) -> Result<ProcedureState, ProcedureError> {
|
||||
match action {
|
||||
ProcedureAction::SelectRole => {
|
||||
(self.state == ProcedureState::Init)
|
||||
.then_some(())
|
||||
.ok_or(ProcedureError::InvalidState(action, self.state))?;
|
||||
|
||||
self.state = ProcedureState::Finish;
|
||||
}
|
||||
ProcedureAction::PerformTrigger => (),
|
||||
ProcedureAction::PerformEnd => (),
|
||||
_ => {
|
||||
return Err(ProcedureError::UnsupportedAction(
|
||||
action,
|
||||
self.procedure_type(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.state)
|
||||
}
|
||||
|
||||
fn is_finished(&self) -> bool {
|
||||
self.state == ProcedureState::Finish
|
||||
}
|
||||
}
|
88
nap_gameserver/src/logic/role/avatar.rs
Normal file
88
nap_gameserver/src/logic/role/avatar.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
use proto::{AvatarBin, AvatarInfo, AvatarSkillInfo};
|
||||
|
||||
use super::AvatarSkill;
|
||||
|
||||
pub const AVATAR_TALENT_COUNT: usize = 6;
|
||||
pub struct Avatar {
|
||||
pub template_id: u32,
|
||||
pub level: u32,
|
||||
pub exp: u32,
|
||||
pub star: u32,
|
||||
pub rank: u32,
|
||||
pub unlocked_talent_num: u32,
|
||||
pub skill_list: Vec<AvatarSkill>,
|
||||
pub talent_switch: [bool; AVATAR_TALENT_COUNT],
|
||||
}
|
||||
|
||||
impl Avatar {
|
||||
pub fn new(template_id: u32) -> Self {
|
||||
Self {
|
||||
template_id,
|
||||
level: 60,
|
||||
exp: 0,
|
||||
star: 0,
|
||||
rank: 6,
|
||||
unlocked_talent_num: 6,
|
||||
skill_list: (0..=6)
|
||||
.map(|st| AvatarSkill {
|
||||
skill_type: st,
|
||||
level: 1,
|
||||
})
|
||||
.collect(),
|
||||
talent_switch: [true; AVATAR_TALENT_COUNT],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bin(bin: AvatarBin) -> Self {
|
||||
Self {
|
||||
template_id: bin.template_id,
|
||||
level: bin.level,
|
||||
exp: bin.exp,
|
||||
star: bin.star,
|
||||
rank: bin.rank,
|
||||
unlocked_talent_num: bin.unlocked_talent_num,
|
||||
skill_list: bin
|
||||
.avatar_skill_list
|
||||
.into_iter()
|
||||
.map(AvatarSkill::from_bin)
|
||||
.collect(),
|
||||
talent_switch: bin
|
||||
.talent_switch_list
|
||||
.try_into()
|
||||
.unwrap_or([false; AVATAR_TALENT_COUNT]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> AvatarBin {
|
||||
AvatarBin {
|
||||
template_id: self.template_id,
|
||||
exp: self.exp,
|
||||
level: self.level,
|
||||
star: self.star,
|
||||
rank: self.rank,
|
||||
unlocked_talent_num: self.unlocked_talent_num,
|
||||
avatar_skill_list: self.skill_list.iter().map(AvatarSkill::to_bin).collect(),
|
||||
talent_switch_list: self.talent_switch.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> AvatarInfo {
|
||||
AvatarInfo {
|
||||
template_id: self.template_id,
|
||||
level: self.level,
|
||||
skill_list: self
|
||||
.skill_list
|
||||
.iter()
|
||||
.map(|s| AvatarSkillInfo {
|
||||
skill_type: s.skill_type,
|
||||
level: s.level,
|
||||
})
|
||||
.collect(),
|
||||
exp: self.exp, // exp?
|
||||
rank: self.rank,
|
||||
talent_switch_list: self.talent_switch.to_vec(),
|
||||
unlocked_talent_num: self.unlocked_talent_num,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
7
nap_gameserver/src/logic/role/mod.rs
Normal file
7
nap_gameserver/src/logic/role/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
mod avatar;
|
||||
mod role_model;
|
||||
mod skill;
|
||||
|
||||
pub use avatar::Avatar;
|
||||
pub use role_model::RoleModel;
|
||||
pub use skill::AvatarSkill;
|
34
nap_gameserver/src/logic/role/role_model.rs
Normal file
34
nap_gameserver/src/logic/role/role_model.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use data::tables;
|
||||
use proto::RoleModelBin;
|
||||
|
||||
use crate::logic::role::Avatar;
|
||||
|
||||
pub struct RoleModel {
|
||||
pub avatar_list: Vec<Avatar>,
|
||||
}
|
||||
|
||||
impl Default for RoleModel {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
avatar_list: tables::avatar_base_template_tb::iter()
|
||||
.map(|a| a.id)
|
||||
.filter(|tmpl_id| *tmpl_id < 2000)
|
||||
.map(|tmpl_id| Avatar::new(tmpl_id))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RoleModel {
|
||||
pub fn from_bin(bin: RoleModelBin) -> Self {
|
||||
Self {
|
||||
avatar_list: bin.avatar_list.into_iter().map(Avatar::from_bin).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> RoleModelBin {
|
||||
RoleModelBin {
|
||||
avatar_list: self.avatar_list.iter().map(Avatar::to_bin).collect(),
|
||||
}
|
||||
}
|
||||
}
|
22
nap_gameserver/src/logic/role/skill.rs
Normal file
22
nap_gameserver/src/logic/role/skill.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use proto::AvatarSkillBin;
|
||||
|
||||
pub struct AvatarSkill {
|
||||
pub skill_type: u32,
|
||||
pub level: u32,
|
||||
}
|
||||
|
||||
impl AvatarSkill {
|
||||
pub fn from_bin(bin: AvatarSkillBin) -> Self {
|
||||
Self {
|
||||
skill_type: bin.skill_type,
|
||||
level: bin.level,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> AvatarSkillBin {
|
||||
AvatarSkillBin {
|
||||
skill_type: self.skill_type,
|
||||
level: self.level,
|
||||
}
|
||||
}
|
||||
}
|
102
nap_gameserver/src/logic/time.rs
Normal file
102
nap_gameserver/src/logic/time.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
use proto::MainCityTimeBin;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MainCityTime {
|
||||
pub day_of_week: DayOfWeek,
|
||||
pub time_of_day: TimeOfDay,
|
||||
}
|
||||
|
||||
impl MainCityTime {
|
||||
const DEFAULT_DAY: u32 = 1;
|
||||
const DEFAULT_TIME: u32 = 1080;
|
||||
|
||||
pub fn tick(&mut self) {
|
||||
if self.time_of_day.tick() {
|
||||
self.day_of_week.next();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fast_forward(&mut self, minutes: u32) {
|
||||
let days_passed = self.time_of_day.fast_forward(minutes);
|
||||
self.day_of_week.fast_forward(days_passed)
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> MainCityTimeBin {
|
||||
MainCityTimeBin {
|
||||
minutes: self.time_of_day.value(),
|
||||
day: self.day_of_week.value(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bin(bin: MainCityTimeBin) -> Self {
|
||||
Self {
|
||||
time_of_day: TimeOfDay::new(bin.minutes),
|
||||
day_of_week: DayOfWeek::new(bin.day),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MainCityTime {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
day_of_week: DayOfWeek::new(Self::DEFAULT_DAY),
|
||||
time_of_day: TimeOfDay::new(Self::DEFAULT_TIME),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DayOfWeek(u32);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TimeOfDay(u32);
|
||||
|
||||
impl DayOfWeek {
|
||||
const DAYS: u32 = 7;
|
||||
|
||||
pub fn new(day: u32) -> Self {
|
||||
Self(day % Self::DAYS)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
self.0 = (self.0 + 1) % Self::DAYS
|
||||
}
|
||||
|
||||
pub fn fast_forward(&mut self, days: u32) {
|
||||
self.0 = (self.0 + days) % Self::DAYS
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeOfDay {
|
||||
const TIME_PERIOD: u32 = 1440;
|
||||
|
||||
pub fn new(minutes: u32) -> Self {
|
||||
Self(minutes % Self::TIME_PERIOD)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
(self.0 % Self::TIME_PERIOD) == 0
|
||||
}
|
||||
|
||||
pub fn tick(&mut self) -> bool {
|
||||
self.0 = (self.0 + 1) % Self::TIME_PERIOD;
|
||||
self.is_zero()
|
||||
}
|
||||
|
||||
pub fn fast_forward(&mut self, minutes: u32) -> u32 {
|
||||
self.0 += minutes;
|
||||
|
||||
let days_passed = self.0 / Self::TIME_PERIOD;
|
||||
self.0 %= Self::TIME_PERIOD;
|
||||
|
||||
days_passed
|
||||
}
|
||||
}
|
45
nap_gameserver/src/main.rs
Normal file
45
nap_gameserver/src/main.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use std::{error::Error, sync::Arc};
|
||||
|
||||
use common::{init_tracing, splash, util::load_or_create_config};
|
||||
use config::NapGSConfig;
|
||||
use data::init_data;
|
||||
use logic::player::PlayerManager;
|
||||
use net::NetSessionManager;
|
||||
|
||||
mod config;
|
||||
mod database;
|
||||
mod handlers;
|
||||
mod logic;
|
||||
mod net;
|
||||
|
||||
pub struct ServerState {
|
||||
pub session_mgr: NetSessionManager,
|
||||
pub player_mgr: PlayerManager,
|
||||
pub config: NapGSConfig,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
splash::print("GameServer");
|
||||
init_tracing();
|
||||
tracing::info!("don't forget to visit https://discord.xeondev.com/");
|
||||
|
||||
let config = load_or_create_config::<NapGSConfig>("nap_gameserver.toml");
|
||||
init_data(&config.assets).expect("failed to init data");
|
||||
|
||||
let pg_pool = match common::database::init(&config.database_credentials).await {
|
||||
Ok(pool) => pool,
|
||||
Err(err) => {
|
||||
tracing::error!("failed to connect to database: {err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let state = ServerState {
|
||||
session_mgr: NetSessionManager::new(),
|
||||
player_mgr: PlayerManager::new(pg_pool),
|
||||
config,
|
||||
};
|
||||
|
||||
net::listen(Arc::new(state)).await
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue