Merge branch 'main' into feature/quest-enum

# Conflicts:
#	server/channelserver/handlers_quest.go
This commit is contained in:
wish
2022-11-01 12:24:23 +11:00
94 changed files with 2906 additions and 2670 deletions

View File

@@ -27,7 +27,7 @@ jobs:
./www/
./savedata/
./bin/
./RoadShopItems.csv
./bundled-schema/
- name: Build Windows-amd64
run: env GOOS=windows GOARCH=amd64 go build -v
@@ -42,4 +42,4 @@ jobs:
./www/
./savedata/
./bin/
./RoadShopItems.csv
./bundled-schema/

View File

@@ -1,8 +1,18 @@
# Erupe Community Edition
## Setup
- If you are only looking to install Erupe, please use [a pre-compiled binary](https://github.com/ZeruLight/Erupe/releases/latest).
- If you want to modify or compile Erupe yourself please read on.
### Requirements
- [Go](https://go.dev/dl/)
- [PostgreSQL](https://www.postgresql.org/download/)
### Installation
1. Bring up a fresh database by using the [backup file attached with the latest release](https://github.com/ZeruLight/Erupe/releases/latest/download/Erupe.sql).
2. Run each script under [patch-schema](./patch-schema) as they introduce newer schema.
3. Edit [config.json](./config.json) such that the database password matches your PostgreSQL setup.
4. Run `go build` or `go run .` to compile Erupe.
### Note
- You will need to acquire and install the client files and quest binaries separately.
# Resources
[Community FAQ Pastebin](https://pastebin.com/QqAwZSTC)
This is a community upload of a community project. The amount of people who worked on it is innumerous, and hard to keep track of. Credits to Andoryuuta, Fist's Team, the French Team, Mai's Team and many others. No matter the relations, these files will remain public and open source, free for all to use and modify.
[A pastebin with various links, tips, and FAQ](https://pastebin.com/QqAwZSTC)
[An upload for the quest and scenario files exists here](https://github.com/xl3lackout/MHFZ-Quest-Files)
(Over 300k+ files)
[Quests and Scenario Binary Files](https://github.com/xl3lackout/MHFZ-Quest-Files)

View File

@@ -1,911 +0,0 @@
10,6,1,2146,25,1,0,0,1,1,0,1,0,0
10,6,2,2147,25,1,0,0,1,1,0,1,0,0
10,6,3,2148,25,1,0,0,1,1,0,1,0,0
10,6,4,2149,25,1,0,0,1,1,0,1,0,0
10,6,5,2150,25,1,0,0,1,1,0,1,0,0
10,6,6,2151,25,1,0,0,1,1,0,1,0,0
10,6,7,2152,25,1,0,0,1,1,0,1,0,0
10,6,8,2153,25,1,0,0,1,1,0,1,0,0
10,6,9,2154,25,1,0,0,1,1,0,1,0,0
10,6,10,2155,25,1,0,0,1,1,0,1,0,0
10,6,11,4398,25,1,0,0,1,1,0,1,0,0
10,6,12,12460,25,1,0,0,1,1,0,1,0,0
10,6,13,12461,25,1,0,0,1,1,0,1,0,0
10,6,14,12462,25,1,0,0,1,1,0,1,0,0
10,6,15,12463,25,1,0,0,1,1,0,1,0,0
10,6,16,12464,25,1,0,0,1,1,0,1,0,0
10,6,17,12465,25,1,0,0,1,1,0,1,0,0
10,6,18,12466,25,1,0,0,1,1,0,1,0,0
10,6,19,12467,25,1,0,0,1,1,0,1,0,0
10,6,20,12468,25,1,0,0,1,1,0,1,0,0
10,6,21,12469,25,1,0,0,1,1,0,1,0,0
10,6,22,15109,1000,1,0,0,1,1,0,1,0,0
10,6,23,15110,1000,1,0,0,1,1,0,1,0,0
10,6,24,2158,200,100,0,0,1,1,0,1,0,0
10,6,25,12306,2,1,0,0,1,1,0,1,80,0
10,6,26,12306,20000,10000,0,0,1,1,0,1,80,0
10,4,27,11664,20000,1,0,0,1,1,0,1,0,0
10,4,28,11665,20000,1,0,0,1,1,0,1,0,0
10,4,29,11666,20000,1,0,0,1,1,0,1,0,0
10,4,30,11667,20000,1,0,0,1,1,0,1,0,0
10,4,31,11668,20000,1,0,0,1,1,0,1,0,0
10,4,32,11669,20000,1,0,0,1,1,0,1,0,0
10,4,33,11670,20000,1,0,0,1,1,0,1,0,0
10,4,34,11671,20000,1,0,0,1,1,0,1,0,0
10,4,35,11672,20000,1,0,0,1,1,0,1,0,0
10,4,36,11673,20000,1,0,0,1,1,0,1,0,0
10,4,37,11674,20000,1,0,0,1,1,0,1,0,0
10,4,38,11675,20000,1,0,0,1,1,0,1,0,0
10,4,39,11676,20000,1,0,0,1,1,0,1,0,0
10,4,40,11677,20000,1,0,0,1,1,0,1,0,0
10,4,41,11678,20000,1,0,0,1,1,0,1,0,0
10,4,42,11679,20000,1,0,0,1,1,0,1,0,0
10,4,43,11680,20000,1,0,0,1,1,0,1,0,0
10,4,44,11681,20000,1,0,0,1,1,0,1,0,0
10,4,45,11682,20000,1,0,0,1,1,0,1,0,0
10,4,46,11683,20000,1,0,0,1,1,0,1,0,0
10,4,47,11684,20000,1,0,0,1,1,0,1,0,0
10,4,48,11685,20000,1,0,0,1,1,0,1,0,0
10,4,49,11686,20000,1,0,0,1,1,0,1,0,0
10,4,50,11687,20000,1,0,0,1,1,0,1,0,0
10,4,51,11688,20000,1,0,0,1,1,0,1,0,0
10,4,52,11689,20000,1,0,0,1,1,0,1,0,0
10,4,53,11690,20000,1,0,0,1,1,0,1,0,0
10,4,54,11691,20000,1,0,0,1,1,0,1,0,0
10,4,55,11692,20000,1,0,0,1,1,0,1,0,0
10,4,56,11693,20000,1,0,0,1,1,0,1,0,0
10,4,57,11694,20000,1,0,0,1,1,0,1,0,0
10,4,58,11695,20000,1,0,0,1,1,0,1,0,0
10,4,59,11696,20000,1,0,0,1,1,0,1,0,0
10,4,60,11697,20000,1,0,0,1,1,0,1,0,0
10,4,61,12893,20000,1,0,0,1,1,0,1,0,0
10,4,62,12894,20000,1,0,0,1,1,0,1,0,0
10,4,63,12895,20000,1,0,0,1,1,0,1,0,0
10,4,64,12896,20000,1,0,0,1,1,0,1,0,0
10,4,65,12897,20000,1,0,0,1,1,0,1,0,0
10,4,66,12898,20000,1,0,0,1,1,0,1,0,0
10,4,67,12899,20000,1,0,0,1,1,0,1,0,0
10,4,68,14337,20000,1,0,0,1,1,0,1,0,0
10,4,69,14338,20000,1,0,0,1,1,0,1,0,0
10,4,70,14339,20000,1,0,0,1,1,0,1,0,0
10,4,71,14340,20000,1,0,0,1,1,0,1,0,0
10,4,72,14341,20000,1,0,0,1,1,0,1,0,0
10,4,73,14342,20000,1,0,0,1,1,0,1,0,0
10,4,74,14343,20000,1,0,0,1,1,0,1,0,0
10,4,75,14344,20000,1,0,0,1,1,0,1,0,0
10,4,76,14345,20000,1,0,0,1,1,0,1,0,0
10,4,77,9254,10000,1,0,0,1,1,0,1,0,0
10,4,78,9255,10000,1,0,0,1,1,0,1,0,0
10,4,79,9256,10000,1,0,0,1,1,0,1,0,0
10,4,80,9257,10000,1,0,0,1,1,0,1,0,0
10,4,81,9258,10000,1,0,0,1,1,0,1,0,0
10,4,82,9259,10000,1,0,0,1,1,0,1,0,0
10,4,83,9260,10000,1,0,0,1,1,0,1,0,0
10,4,84,9261,10000,1,0,0,1,1,0,1,0,0
10,4,85,9262,10000,1,0,0,1,1,0,1,0,0
10,4,86,9263,10000,1,0,0,1,1,0,1,0,0
10,4,87,9264,10000,1,0,0,1,1,0,1,0,0
10,4,88,9265,10000,1,0,0,1,1,0,1,0,0
10,4,89,9266,10000,1,0,0,1,1,0,1,0,0
10,4,90,9267,10000,1,0,0,1,1,0,1,0,0
10,4,91,9268,10000,1,0,0,1,1,0,1,0,0
10,4,92,9269,10000,1,0,0,1,1,0,1,0,0
10,4,93,9270,10000,1,0,0,1,1,0,1,0,0
10,4,94,9271,10000,1,0,0,1,1,0,1,0,0
10,4,95,9272,10000,1,0,0,1,1,0,1,0,0
10,4,96,9273,10000,1,0,0,1,1,0,1,0,0
10,4,97,9274,10000,1,0,0,1,1,0,1,0,0
10,4,98,9275,10000,1,0,0,1,1,0,1,0,0
10,4,99,9276,10000,1,0,0,1,1,0,1,0,0
10,4,100,9277,10000,1,0,0,1,1,0,1,0,0
10,4,101,9278,10000,1,0,0,1,1,0,1,0,0
10,4,102,9279,10000,1,0,0,1,1,0,1,0,0
10,4,103,9280,10000,1,0,0,1,1,0,1,0,0
10,4,104,9281,10000,1,0,0,1,1,0,1,0,0
10,4,105,9282,10000,1,0,0,1,1,0,1,0,0
10,4,106,9283,10000,1,0,0,1,1,0,1,0,0
10,4,107,9284,10000,1,0,0,1,1,0,1,0,0
10,4,108,9285,10000,1,0,0,1,1,0,1,0,0
10,4,109,9286,10000,1,0,0,1,1,0,1,0,0
10,4,110,9287,10000,1,0,0,1,1,0,1,0,0
10,4,111,9288,10000,1,0,0,1,1,0,1,0,0
10,4,112,9289,10000,1,0,0,1,1,0,1,0,0
10,4,113,9290,10000,1,0,0,1,1,0,1,0,0
10,4,114,9291,10000,1,0,0,1,1,0,1,0,0
10,4,115,9292,10000,1,0,0,1,1,0,1,0,0
10,4,116,9293,10000,1,0,0,1,1,0,1,0,0
10,4,117,9294,10000,1,0,0,1,1,0,1,0,0
10,4,118,9295,10000,1,0,0,1,1,0,1,0,0
10,4,119,9296,10000,1,0,0,1,1,0,1,0,0
10,4,120,9297,10000,1,0,0,1,1,0,1,0,0
10,4,121,9298,10000,1,0,0,1,1,0,1,0,0
10,4,122,9299,10000,1,0,0,1,1,0,1,0,0
10,4,123,9300,10000,1,0,0,1,1,0,1,0,0
10,4,124,9301,10000,1,0,0,1,1,0,1,0,0
10,4,125,13196,10000,1,0,0,1,1,0,1,0,0
10,4,126,13197,10000,1,0,0,1,1,0,1,0,0
10,4,127,13198,10000,1,0,0,1,1,0,1,0,0
10,4,128,13199,10000,1,0,0,1,1,0,1,0,0
10,4,129,15542,10000,1,0,0,1,1,0,1,0,0
10,4,130,15543,10000,1,0,0,1,1,0,1,0,0
10,4,131,15544,10000,1,0,0,1,1,0,1,0,0
10,4,132,15545,10000,1,0,0,1,1,0,1,0,0
10,4,133,13640,20000,1,0,0,1,1,0,1,0,0
10,4,134,13641,20000,1,0,0,1,1,0,1,0,0
10,4,135,13642,20000,1,0,0,1,1,0,1,0,0
10,4,136,13643,20000,1,0,0,1,1,0,1,0,0
10,4,137,13644,20000,1,0,0,1,1,0,1,0,0
10,4,138,13645,20000,1,0,0,1,1,0,1,0,0
10,4,139,13646,20000,1,0,0,1,1,0,1,0,0
10,4,140,13647,20000,1,0,0,1,1,0,1,0,0
10,4,141,13648,20000,1,0,0,1,1,0,1,0,0
10,4,142,13649,20000,1,0,0,1,1,0,1,0,0
10,4,143,13650,20000,1,0,0,1,1,0,1,0,0
10,4,144,13651,20000,1,0,0,1,1,0,1,0,0
10,4,145,13652,20000,1,0,0,1,1,0,1,0,0
10,4,146,13653,20000,1,0,0,1,1,0,1,0,0
10,4,147,13654,20000,1,0,0,1,1,0,1,0,0
10,4,148,13655,20000,1,0,0,1,1,0,1,0,0
10,4,149,13656,20000,1,0,0,1,1,0,1,0,0
10,4,150,13657,20000,1,0,0,1,1,0,1,0,0
10,4,151,13658,20000,1,0,0,1,1,0,1,0,0
10,4,152,13659,20000,1,0,0,1,1,0,1,0,0
10,4,153,13660,20000,1,0,0,1,1,0,1,0,0
10,4,154,13661,20000,1,0,0,1,1,0,1,0,0
10,4,155,13662,20000,1,0,0,1,1,0,1,0,0
10,4,156,13663,20000,1,0,0,1,1,0,1,0,0
10,4,157,13664,20000,1,0,0,1,1,0,1,0,0
10,4,158,13665,20000,1,0,0,1,1,0,1,0,0
10,4,159,13666,20000,1,0,0,1,1,0,1,0,0
10,4,160,13667,20000,1,0,0,1,1,0,1,0,0
10,4,161,13668,20000,1,0,0,1,1,0,1,0,0
10,4,162,13669,20000,1,0,0,1,1,0,1,0,0
10,4,163,13670,20000,1,0,0,1,1,0,1,0,0
10,4,164,13671,20000,1,0,0,1,1,0,1,0,0
10,4,165,13672,20000,1,0,0,1,1,0,1,0,0
10,4,166,13673,20000,1,0,0,1,1,0,1,0,0
10,4,167,13674,20000,1,0,0,1,1,0,1,0,0
10,4,168,13675,20000,1,0,0,1,1,0,1,0,0
10,4,169,13676,20000,1,0,0,1,1,0,1,0,0
10,4,170,13677,20000,1,0,0,1,1,0,1,0,0
10,4,171,13678,20000,1,0,0,1,1,0,1,0,0
10,4,172,13679,20000,1,0,0,1,1,0,1,0,0
10,4,173,13680,20000,1,0,0,1,1,0,1,0,0
10,4,174,13681,20000,1,0,0,1,1,0,1,0,0
10,4,175,13682,20000,1,0,0,1,1,0,1,0,0
10,4,176,13683,20000,1,0,0,1,1,0,1,0,0
10,4,177,13684,20000,1,0,0,1,1,0,1,0,0
10,4,178,13685,20000,1,0,0,1,1,0,1,0,0
10,4,179,13686,20000,1,0,0,1,1,0,1,0,0
10,4,180,13687,20000,1,0,0,1,1,0,1,0,0
10,4,181,13688,20000,1,0,0,1,1,0,1,0,0
10,4,182,13689,20000,1,0,0,1,1,0,1,0,0
10,4,183,13690,20000,1,0,0,1,1,0,1,0,0
10,4,184,13691,20000,1,0,0,1,1,0,1,0,0
10,4,185,15546,20000,1,0,0,1,1,0,1,0,0
10,4,186,15547,20000,1,0,0,1,1,0,1,0,0
10,4,187,15548,20000,1,0,0,1,1,0,1,0,0
10,4,188,15549,20000,1,0,0,1,1,0,1,0,0
10,4,189,16162,35000,1,0,0,1,1,0,1,0,0
10,4,190,16163,35000,1,0,0,1,1,0,1,0,0
10,4,191,16164,35000,1,0,0,1,1,0,1,0,0
10,4,192,16165,35000,1,0,0,1,1,0,1,0,0
10,4,193,16166,35000,1,0,0,1,1,0,1,0,0
10,4,194,16167,35000,1,0,0,1,1,0,1,0,0
10,4,195,16168,35000,1,0,0,1,1,0,1,0,0
10,4,196,16169,35000,1,0,0,1,1,0,1,0,0
10,4,197,16172,35000,1,0,0,1,1,0,1,0,0
10,4,198,16173,35000,1,0,0,1,1,0,1,0,0
10,4,199,16174,35000,1,0,0,1,1,0,1,0,0
10,4,200,16175,35000,1,0,0,1,1,0,1,0,0
10,4,201,16176,35000,1,0,0,1,1,0,1,0,0
10,4,202,16177,35000,1,0,0,1,1,0,1,0,0
10,4,203,16178,35000,1,0,0,1,1,0,1,0,0
10,4,204,16179,35000,1,0,0,1,1,0,1,0,0
10,4,205,16182,35000,1,0,0,1,1,0,1,0,0
10,4,206,16183,35000,1,0,0,1,1,0,1,0,0
10,4,207,16184,35000,1,0,0,1,1,0,1,0,0
10,4,208,16185,35000,1,0,0,1,1,0,1,0,0
10,4,209,16186,35000,1,0,0,1,1,0,1,0,0
10,4,210,16187,35000,1,0,0,1,1,0,1,0,0
10,4,211,16188,35000,1,0,0,1,1,0,1,0,0
10,4,212,16189,35000,1,0,0,1,1,0,1,0,0
10,4,213,16192,35000,1,0,0,1,1,0,1,0,0
10,4,214,16193,35000,1,0,0,1,1,0,1,0,0
10,4,215,16194,35000,1,0,0,1,1,0,1,0,0
10,4,216,16195,35000,1,0,0,1,1,0,1,0,0
10,4,217,16196,35000,1,0,0,1,1,0,1,0,0
10,4,218,16197,35000,1,0,0,1,1,0,1,0,0
10,4,219,16198,35000,1,0,0,1,1,0,1,0,0
10,4,220,16199,35000,1,0,0,1,1,0,1,0,0
10,4,221,16202,35000,1,0,0,1,1,0,1,0,0
10,4,222,16203,35000,1,0,0,1,1,0,1,0,0
10,4,223,16204,35000,1,0,0,1,1,0,1,0,0
10,4,224,16205,35000,1,0,0,1,1,0,1,0,0
10,4,225,16206,35000,1,0,0,1,1,0,1,0,0
10,4,226,16207,35000,1,0,0,1,1,0,1,0,0
10,4,227,16208,35000,1,0,0,1,1,0,1,0,0
10,4,228,16209,35000,1,0,0,1,1,0,1,0,0
10,4,229,16212,35000,1,0,0,1,1,0,1,0,0
10,4,230,16213,35000,1,0,0,1,1,0,1,0,0
10,4,231,16214,35000,1,0,0,1,1,0,1,0,0
10,4,232,16215,35000,1,0,0,1,1,0,1,0,0
10,4,233,16216,35000,1,0,0,1,1,0,1,0,0
10,4,234,16217,35000,1,0,0,1,1,0,1,0,0
10,4,235,16218,35000,1,0,0,1,1,0,1,0,0
10,4,236,16219,35000,1,0,0,1,1,0,1,0,0
10,4,237,16222,35000,1,0,0,1,1,0,1,0,0
10,4,238,16223,35000,1,0,0,1,1,0,1,0,0
10,4,239,16224,35000,1,0,0,1,1,0,1,0,0
10,4,240,16225,35000,1,0,0,1,1,0,1,0,0
10,4,241,16226,35000,1,0,0,1,1,0,1,0,0
10,4,242,16227,35000,1,0,0,1,1,0,1,0,0
10,4,243,16228,35000,1,0,0,1,1,0,1,0,0
10,4,244,16229,35000,1,0,0,1,1,0,1,0,0
10,4,245,16232,35000,1,0,0,1,1,0,1,0,0
10,4,246,16233,35000,1,0,0,1,1,0,1,0,0
10,4,247,16234,35000,1,0,0,1,1,0,1,0,0
10,4,248,16235,35000,1,0,0,1,1,0,1,0,0
10,4,249,16236,35000,1,0,0,1,1,0,1,0,0
10,4,250,16237,35000,1,0,0,1,1,0,1,0,0
10,4,251,16238,35000,1,0,0,1,1,0,1,0,0
10,4,252,16239,35000,1,0,0,1,1,0,1,0,0
10,4,253,16242,35000,1,0,0,1,1,0,1,0,0
10,4,254,16243,35000,1,0,0,1,1,0,1,0,0
10,4,255,16244,35000,1,0,0,1,1,0,1,0,0
10,4,256,16245,35000,1,0,0,1,1,0,1,0,0
10,4,257,16246,35000,1,0,0,1,1,0,1,0,0
10,4,258,16247,35000,1,0,0,1,1,0,1,0,0
10,4,259,16248,35000,1,0,0,1,1,0,1,0,0
10,4,260,16249,35000,1,0,0,1,1,0,1,0,0
10,4,261,16252,35000,1,0,0,1,1,0,1,0,0
10,4,262,16253,35000,1,0,0,1,1,0,1,0,0
10,4,263,16254,35000,1,0,0,1,1,0,1,0,0
10,4,264,16255,35000,1,0,0,1,1,0,1,0,0
10,4,265,16256,35000,1,0,0,1,1,0,1,0,0
10,4,266,16257,35000,1,0,0,1,1,0,1,0,0
10,4,267,16258,35000,1,0,0,1,1,0,1,0,0
10,4,268,16259,35000,1,0,0,1,1,0,1,0,0
10,4,269,16262,35000,1,0,0,1,1,0,1,0,0
10,4,270,16263,35000,1,0,0,1,1,0,1,0,0
10,4,271,16264,35000,1,0,0,1,1,0,1,0,0
10,4,272,16265,35000,1,0,0,1,1,0,1,0,0
10,4,273,16266,35000,1,0,0,1,1,0,1,0,0
10,4,274,16267,35000,1,0,0,1,1,0,1,0,0
10,4,275,16268,35000,1,0,0,1,1,0,1,0,0
10,4,276,16269,35000,1,0,0,1,1,0,1,0,0
10,4,277,16272,35000,1,0,0,1,1,0,1,0,0
10,4,278,16273,35000,1,0,0,1,1,0,1,0,0
10,4,279,16274,35000,1,0,0,1,1,0,1,0,0
10,4,280,16275,35000,1,0,0,1,1,0,1,0,0
10,4,281,16276,35000,1,0,0,1,1,0,1,0,0
10,4,282,16277,35000,1,0,0,1,1,0,1,0,0
10,4,283,16278,35000,1,0,0,1,1,0,1,0,0
10,4,284,16279,35000,1,0,0,1,1,0,1,0,0
10,4,285,16282,35000,1,0,0,1,1,0,1,0,0
10,4,286,16283,35000,1,0,0,1,1,0,1,0,0
10,4,287,16284,35000,1,0,0,1,1,0,1,0,0
10,4,288,16285,35000,1,0,0,1,1,0,1,0,0
10,4,289,16286,35000,1,0,0,1,1,0,1,0,0
10,4,290,16287,35000,1,0,0,1,1,0,1,0,0
10,4,291,16288,35000,1,0,0,1,1,0,1,0,0
10,4,292,16289,35000,1,0,0,1,1,0,1,0,0
10,4,293,16292,35000,1,0,0,1,1,0,1,0,0
10,4,294,16293,35000,1,0,0,1,1,0,1,0,0
10,4,295,16294,35000,1,0,0,1,1,0,1,0,0
10,4,296,16295,35000,1,0,0,1,1,0,1,0,0
10,4,297,16296,35000,1,0,0,1,1,0,1,0,0
10,4,298,16297,35000,1,0,0,1,1,0,1,0,0
10,4,299,16298,35000,1,0,0,1,1,0,1,0,0
10,4,300,16299,35000,1,0,0,1,1,0,1,0,0
10,8,301,14136,15000,1,0,0,1,1,0,1,0,0
10,8,302,14137,15000,1,0,0,1,1,0,1,0,0
10,8,303,14138,15000,1,0,0,1,1,0,1,0,0
10,8,304,14139,15000,1,0,0,1,1,0,1,0,0
10,8,305,14140,15000,1,0,0,1,1,0,1,0,0
10,8,306,14141,15000,1,0,0,1,1,0,1,0,0
10,8,307,14142,15000,1,0,0,1,1,0,1,0,0
10,8,308,14143,15000,1,0,0,1,1,0,1,0,0
10,8,309,14144,15000,1,0,0,1,1,0,1,0,0
10,8,310,14145,15000,1,0,0,1,1,0,1,0,0
10,8,311,14454,30000,1,0,0,1,1,0,1,0,0
10,8,312,14455,30000,1,0,0,1,1,0,1,0,0
10,8,313,14456,30000,1,0,0,1,1,0,1,0,0
10,8,314,14457,30000,1,0,0,1,1,0,1,0,0
10,8,315,14458,30000,1,0,0,1,1,0,1,0,0
10,8,316,14459,30000,1,0,0,1,1,0,1,0,0
10,8,317,14460,30000,1,0,0,1,1,0,1,0,0
10,8,318,14461,30000,1,0,0,1,1,0,1,0,0
10,8,319,14462,30000,1,0,0,1,1,0,1,0,0
10,8,320,14463,30000,1,0,0,1,1,0,1,0,0
10,8,321,12724,50000,1,0,0,1,1,0,1,0,0
10,8,322,12725,50000,1,0,0,1,1,0,1,0,0
10,8,323,12726,50000,1,0,0,1,1,0,1,0,0
10,8,324,12727,50000,1,0,0,1,1,0,1,0,0
10,8,325,12728,50000,1,0,0,1,1,0,1,0,0
10,8,326,12729,50000,1,0,0,1,1,0,1,0,0
10,8,327,12730,50000,1,0,0,1,1,0,1,0,0
10,8,328,12731,50000,1,0,0,1,1,0,1,0,0
10,8,329,12732,50000,1,0,0,1,1,0,1,0,0
10,8,330,12733,50000,1,0,0,1,1,0,1,0,0
10,8,331,12734,50000,1,0,0,1,1,0,1,0,0
10,8,332,12735,50000,1,0,0,1,1,0,1,0,0
10,8,333,12736,50000,1,0,0,1,1,0,1,0,0
10,8,334,12737,50000,1,0,0,1,1,0,1,0,0
10,8,335,12738,50000,1,0,0,1,1,0,1,0,0
10,8,336,12739,50000,1,0,0,1,1,0,1,0,0
10,8,337,12740,50000,1,0,0,1,1,0,1,0,0
10,8,338,12741,50000,1,0,0,1,1,0,1,0,0
10,8,339,12742,50000,1,0,0,1,1,0,1,0,0
10,8,340,12743,50000,1,0,0,1,1,0,1,0,0
10,8,341,12744,50000,1,0,0,1,1,0,1,0,0
10,8,342,12745,50000,1,0,0,1,1,0,1,0,0
10,8,343,12746,50000,1,0,0,1,1,0,1,0,0
10,8,344,12747,50000,1,0,0,1,1,0,1,0,0
10,8,345,12748,50000,1,0,0,1,1,0,1,0,0
10,8,346,12749,50000,1,0,0,1,1,0,1,0,0
10,8,347,12750,50000,1,0,0,1,1,0,1,0,0
10,8,348,12751,50000,1,0,0,1,1,0,1,0,0
10,8,349,12752,50000,1,0,0,1,1,0,1,0,0
10,8,350,12753,50000,1,0,0,1,1,0,1,0,0
10,8,351,15070,50000,1,0,0,1,1,0,1,0,0
10,8,352,15071,50000,1,0,0,1,1,0,1,0,0
10,8,353,15072,50000,1,0,0,1,1,0,1,0,0
10,8,354,15073,50000,1,0,0,1,1,0,1,0,0
10,8,355,15074,50000,1,0,0,1,1,0,1,0,0
10,8,356,15075,50000,1,0,0,1,1,0,1,0,0
10,8,357,15076,50000,1,0,0,1,1,0,1,0,0
10,8,358,15077,50000,1,0,0,1,1,0,1,0,0
10,8,359,15078,50000,1,0,0,1,1,0,1,0,0
10,8,360,15079,50000,1,0,0,1,1,0,1,0,0
10,8,361,15567,20000,1,0,0,1,1,0,1,0,0
10,8,362,15568,20000,1,0,0,1,1,0,1,0,0
10,8,363,15569,20000,1,0,0,1,1,0,1,0,0
10,8,364,15570,20000,1,0,0,1,1,0,1,0,0
10,8,365,15571,20000,1,0,0,1,1,0,1,0,0
10,8,366,15572,20000,1,0,0,1,1,0,1,0,0
10,8,367,15573,20000,1,0,0,1,1,0,1,0,0
10,8,368,15574,20000,1,0,0,1,1,0,1,0,0
10,8,369,15575,20000,1,0,0,1,1,0,1,0,0
10,8,370,15576,20000,1,0,0,1,1,0,1,0,0
10,8,371,15577,20000,1,0,0,1,1,0,1,0,0
10,8,372,15578,20000,1,0,0,1,1,0,1,0,0
10,8,373,15579,20000,1,0,0,1,1,0,1,0,0
10,8,374,15580,20000,1,0,0,1,1,0,1,0,0
10,8,375,15581,20000,1,0,0,1,1,0,1,0,0
10,8,376,15582,20000,1,0,0,1,1,0,1,0,0
10,8,377,15583,20000,1,0,0,1,1,0,1,0,0
10,8,378,15584,20000,1,0,0,1,1,0,1,0,0
10,8,379,15585,20000,1,0,0,1,1,0,1,0,0
10,8,380,15586,20000,1,0,0,1,1,0,1,0,0
10,8,381,15587,20000,1,0,0,1,1,0,1,0,0
10,8,382,15588,20000,1,0,0,1,1,0,1,0,0
10,8,383,15589,20000,1,0,0,1,1,0,1,0,0
10,8,384,15590,20000,1,0,0,1,1,0,1,0,0
10,8,385,15591,20000,1,0,0,1,1,0,1,0,0
10,8,386,15592,20000,1,0,0,1,1,0,1,0,0
10,8,387,15593,20000,1,0,0,1,1,0,1,0,0
10,8,388,15594,20000,1,0,0,1,1,0,1,0,0
10,8,389,15595,20000,1,0,0,1,1,0,1,0,0
10,8,390,15596,20000,1,0,0,1,1,0,1,0,0
10,8,391,15597,20000,1,0,0,1,1,0,1,0,0
10,8,392,15598,20000,1,0,0,1,1,0,1,0,0
10,8,393,15599,20000,1,0,0,1,1,0,1,0,0
10,8,394,15600,20000,1,0,0,1,1,0,1,0,0
10,8,395,15601,20000,1,0,0,1,1,0,1,0,0
10,8,396,15602,20000,1,0,0,1,1,0,1,0,0
10,8,397,15603,20000,1,0,0,1,1,0,1,0,0
10,8,398,15604,20000,1,0,0,1,1,0,1,0,0
10,8,399,15605,20000,1,0,0,1,1,0,1,0,0
10,8,400,15606,20000,1,0,0,1,1,0,1,0,0
10,8,401,15607,20000,1,0,0,1,1,0,1,0,0
10,8,402,15608,20000,1,0,0,1,1,0,1,0,0
10,8,403,15609,20000,1,0,0,1,1,0,1,0,0
10,8,404,15610,20000,1,0,0,1,1,0,1,0,0
10,8,405,15611,20000,1,0,0,1,1,0,1,0,0
10,8,406,15612,20000,1,0,0,1,1,0,1,0,0
10,8,407,15613,20000,1,0,0,1,1,0,1,0,0
10,8,408,15614,20000,1,0,0,1,1,0,1,0,0
10,8,409,15615,20000,1,0,0,1,1,0,1,0,0
10,8,410,15616,20000,1,0,0,1,1,0,1,0,0
10,8,411,15617,20000,1,0,0,1,1,0,1,0,0
10,8,412,15618,20000,1,0,0,1,1,0,1,0,0
10,8,413,15619,20000,1,0,0,1,1,0,1,0,0
10,8,414,15620,20000,1,0,0,1,1,0,1,0,0
10,8,415,15621,20000,1,0,0,1,1,0,1,0,0
10,8,416,15622,20000,1,0,0,1,1,0,1,0,0
10,8,417,15623,20000,1,0,0,1,1,0,1,0,0
10,8,418,15624,20000,1,0,0,1,1,0,1,0,0
10,8,419,15625,20000,1,0,0,1,1,0,1,0,0
10,8,420,15626,20000,1,0,0,1,1,0,1,0,0
10,8,421,15627,20000,1,0,0,1,1,0,1,0,0
10,8,422,15628,20000,1,0,0,1,1,0,1,0,0
10,8,423,15629,20000,1,0,0,1,1,0,1,0,0
10,8,424,15630,20000,1,0,0,1,1,0,1,0,0
10,8,425,15631,20000,1,0,0,1,1,0,1,0,0
10,8,426,15632,20000,1,0,0,1,1,0,1,0,0
10,8,427,15633,20000,1,0,0,1,1,0,1,0,0
10,8,428,15634,20000,1,0,0,1,1,0,1,0,0
10,8,429,15635,20000,1,0,0,1,1,0,1,0,0
10,8,430,15636,20000,1,0,0,1,1,0,1,0,0
10,8,431,15637,20000,1,0,0,1,1,0,1,0,0
10,8,432,15638,20000,1,0,0,1,1,0,1,0,0
10,8,433,15639,20000,1,0,0,1,1,0,1,0,0
10,8,434,15640,20000,1,0,0,1,1,0,1,0,0
10,8,435,15641,20000,1,0,0,1,1,0,1,0,0
10,8,436,15642,20000,1,0,0,1,1,0,1,0,0
10,8,437,15643,20000,1,0,0,1,1,0,1,0,0
10,8,438,15644,20000,1,0,0,1,1,0,1,0,0
10,8,439,15645,20000,1,0,0,1,1,0,1,0,0
10,8,440,15646,20000,1,0,0,1,1,0,1,0,0
10,8,441,15647,20000,1,0,0,1,1,0,1,0,0
10,8,442,15648,20000,1,0,0,1,1,0,1,0,0
10,8,443,15649,20000,1,0,0,1,1,0,1,0,0
10,8,444,15650,20000,1,0,0,1,1,0,1,0,0
10,8,445,15651,20000,1,0,0,1,1,0,1,0,0
10,8,446,15652,20000,1,0,0,1,1,0,1,0,0
10,8,447,15653,20000,1,0,0,1,1,0,1,0,0
10,8,448,15654,20000,1,0,0,1,1,0,1,0,0
10,8,449,15655,20000,1,0,0,1,1,0,1,0,0
10,8,450,15656,20000,1,0,0,1,1,0,1,0,0
10,8,451,15657,20000,1,0,0,1,1,0,1,0,0
10,8,452,15658,20000,1,0,0,1,1,0,1,0,0
10,8,453,15659,20000,1,0,0,1,1,0,1,0,0
10,8,454,15660,20000,1,0,0,1,1,0,1,0,0
10,8,455,15661,20000,1,0,0,1,1,0,1,0,0
10,8,456,15662,20000,1,0,0,1,1,0,1,0,0
10,8,457,15663,20000,1,0,0,1,1,0,1,0,0
10,8,458,15664,20000,1,0,0,1,1,0,1,0,0
10,8,459,15665,20000,1,0,0,1,1,0,1,0,0
10,8,460,15666,20000,1,0,0,1,1,0,1,0,0
10,8,461,15667,20000,1,0,0,1,1,0,1,0,0
10,8,462,15668,20000,1,0,0,1,1,0,1,0,0
10,8,463,15669,20000,1,0,0,1,1,0,1,0,0
10,8,464,15670,20000,1,0,0,1,1,0,1,0,0
10,8,465,15671,20000,1,0,0,1,1,0,1,0,0
10,8,466,15672,20000,1,0,0,1,1,0,1,0,0
10,8,467,15673,20000,1,0,0,1,1,0,1,0,0
10,8,468,15674,20000,1,0,0,1,1,0,1,0,0
10,8,469,15675,20000,1,0,0,1,1,0,1,0,0
10,8,470,15676,20000,1,0,0,1,1,0,1,0,0
10,8,471,15677,20000,1,0,0,1,1,0,1,0,0
10,8,472,15678,20000,1,0,0,1,1,0,1,0,0
10,8,473,15679,20000,1,0,0,1,1,0,1,0,0
10,8,474,15680,20000,1,0,0,1,1,0,1,0,0
10,8,475,15681,20000,1,0,0,1,1,0,1,0,0
10,8,476,15682,20000,1,0,0,1,1,0,1,0,0
10,8,477,15683,20000,1,0,0,1,1,0,1,0,0
10,8,478,15684,20000,1,0,0,1,1,0,1,0,0
10,8,479,15685,20000,1,0,0,1,1,0,1,0,0
10,8,480,15686,20000,1,0,0,1,1,0,1,0,0
10,8,481,15687,20000,1,0,0,1,1,0,1,0,0
10,8,482,15688,20000,1,0,0,1,1,0,1,0,0
10,8,483,15689,20000,1,0,0,1,1,0,1,0,0
10,8,484,15690,20000,1,0,0,1,1,0,1,0,0
10,8,485,15691,20000,1,0,0,1,1,0,1,0,0
10,8,486,15692,20000,1,0,0,1,1,0,1,0,0
10,8,487,15693,20000,1,0,0,1,1,0,1,0,0
10,8,488,15694,20000,1,0,0,1,1,0,1,0,0
10,8,489,15695,20000,1,0,0,1,1,0,1,0,0
10,8,490,15696,20000,1,0,0,1,1,0,1,0,0
10,8,491,15697,20000,1,0,0,1,1,0,1,0,0
10,8,492,15698,20000,1,0,0,1,1,0,1,0,0
10,8,493,15699,20000,1,0,0,1,1,0,1,0,0
10,8,494,15700,20000,1,0,0,1,1,0,1,0,0
10,8,495,15701,20000,1,0,0,1,1,0,1,0,0
10,8,496,15702,20000,1,0,0,1,1,0,1,0,0
10,8,497,15703,20000,1,0,0,1,1,0,1,0,0
10,8,498,15704,20000,1,0,0,1,1,0,1,0,0
10,8,499,15705,20000,1,0,0,1,1,0,1,0,0
10,8,500,15706,20000,1,0,0,1,1,0,1,0,0
10,8,501,15707,20000,1,0,0,1,1,0,1,0,0
10,8,502,15708,20000,1,0,0,1,1,0,1,0,0
10,8,503,15709,20000,1,0,0,1,1,0,1,0,0
10,8,504,15710,20000,1,0,0,1,1,0,1,0,0
10,8,505,15711,20000,1,0,0,1,1,0,1,0,0
10,8,506,15712,20000,1,0,0,1,1,0,1,0,0
10,8,507,15713,20000,1,0,0,1,1,0,1,0,0
10,8,508,15714,20000,1,0,0,1,1,0,1,0,0
10,8,509,15715,20000,1,0,0,1,1,0,1,0,0
10,8,510,15716,20000,1,0,0,1,1,0,1,0,0
10,8,511,15717,20000,1,0,0,1,1,0,1,0,0
10,8,512,15718,20000,1,0,0,1,1,0,1,0,0
10,8,513,15719,20000,1,0,0,1,1,0,1,0,0
10,8,514,15720,20000,1,0,0,1,1,0,1,0,0
10,8,515,15721,20000,1,0,0,1,1,0,1,0,0
10,8,516,15722,20000,1,0,0,1,1,0,1,0,0
10,8,517,15723,20000,1,0,0,1,1,0,1,0,0
10,8,518,15724,20000,1,0,0,1,1,0,1,0,0
10,8,519,15725,20000,1,0,0,1,1,0,1,0,0
10,8,520,15726,20000,1,0,0,1,1,0,1,0,0
10,8,521,15727,20000,1,0,0,1,1,0,1,0,0
10,8,522,15728,20000,1,0,0,1,1,0,1,0,0
10,8,523,15729,20000,1,0,0,1,1,0,1,0,0
10,8,524,15730,20000,1,0,0,1,1,0,1,0,0
10,8,525,15731,20000,1,0,0,1,1,0,1,0,0
10,8,526,15732,20000,1,0,0,1,1,0,1,0,0
10,8,527,15733,20000,1,0,0,1,1,0,1,0,0
10,8,528,15734,20000,1,0,0,1,1,0,1,0,0
10,8,529,15735,20000,1,0,0,1,1,0,1,0,0
10,8,530,15736,20000,1,0,0,1,1,0,1,0,0
10,8,531,15737,20000,1,0,0,1,1,0,1,0,0
10,8,532,15738,20000,1,0,0,1,1,0,1,0,0
10,8,533,15739,20000,1,0,0,1,1,0,1,0,0
10,8,534,15740,20000,1,0,0,1,1,0,1,0,0
10,8,535,15741,20000,1,0,0,1,1,0,1,0,0
10,8,536,15742,20000,1,0,0,1,1,0,1,0,0
10,8,537,15743,20000,1,0,0,1,1,0,1,0,0
10,8,538,15744,20000,1,0,0,1,1,0,1,0,0
10,8,539,15745,20000,1,0,0,1,1,0,1,0,0
10,8,540,15746,20000,1,0,0,1,1,0,1,0,0
10,8,541,15747,20000,1,0,0,1,1,0,1,0,0
10,8,542,15748,20000,1,0,0,1,1,0,1,0,0
10,8,543,15749,20000,1,0,0,1,1,0,1,0,0
10,8,544,15750,20000,1,0,0,1,1,0,1,0,0
10,8,545,15751,20000,1,0,0,1,1,0,1,0,0
10,8,546,15752,20000,1,0,0,1,1,0,1,0,0
10,8,547,15753,20000,1,0,0,1,1,0,1,0,0
10,8,548,15754,20000,1,0,0,1,1,0,1,0,0
10,8,549,15755,20000,1,0,0,1,1,0,1,0,0
10,8,550,15756,20000,1,0,0,1,1,0,1,0,0
10,8,551,15757,20000,1,0,0,1,1,0,1,0,0
10,8,552,15758,20000,1,0,0,1,1,0,1,0,0
10,8,553,15759,20000,1,0,0,1,1,0,1,0,0
10,8,554,15760,20000,1,0,0,1,1,0,1,0,0
10,8,555,15761,20000,1,0,0,1,1,0,1,0,0
10,8,556,15762,20000,1,0,0,1,1,0,1,0,0
10,8,557,15763,20000,1,0,0,1,1,0,1,0,0
10,8,558,15764,20000,1,0,0,1,1,0,1,0,0
10,8,559,15765,20000,1,0,0,1,1,0,1,0,0
10,8,560,15766,20000,1,0,0,1,1,0,1,0,0
10,8,561,15919,20000,1,0,0,1,1,0,1,0,0
10,8,562,15920,20000,1,0,0,1,1,0,1,0,0
10,8,563,15921,20000,1,0,0,1,1,0,1,0,0
10,8,564,15922,20000,1,0,0,1,1,0,1,0,0
10,8,565,15923,20000,1,0,0,1,1,0,1,0,0
10,8,566,15924,20000,1,0,0,1,1,0,1,0,0
10,8,567,15925,20000,1,0,0,1,1,0,1,0,0
10,8,568,15926,20000,1,0,0,1,1,0,1,0,0
10,8,569,15927,20000,1,0,0,1,1,0,1,0,0
10,8,570,15928,20000,1,0,0,1,1,0,1,0,0
10,8,571,15929,20000,1,0,0,1,1,0,1,0,0
10,8,572,15930,20000,1,0,0,1,1,0,1,0,0
10,8,573,15931,20000,1,0,0,1,1,0,1,0,0
10,8,574,15932,20000,1,0,0,1,1,0,1,0,0
10,8,575,15933,20000,1,0,0,1,1,0,1,0,0
10,8,576,15934,20000,1,0,0,1,1,0,1,0,0
10,8,577,15935,20000,1,0,0,1,1,0,1,0,0
10,8,578,15936,20000,1,0,0,1,1,0,1,0,0
10,8,579,15937,20000,1,0,0,1,1,0,1,0,0
10,8,580,15938,20000,1,0,0,1,1,0,1,0,0
10,8,581,15939,20000,1,0,0,1,1,0,1,0,0
10,8,582,15940,20000,1,0,0,1,1,0,1,0,0
10,8,583,15941,20000,1,0,0,1,1,0,1,0,0
10,8,584,15942,20000,1,0,0,1,1,0,1,0,0
10,8,585,15943,20000,1,0,0,1,1,0,1,0,0
10,8,586,15944,20000,1,0,0,1,1,0,1,0,0
10,8,587,15945,20000,1,0,0,1,1,0,1,0,0
10,8,588,15946,20000,1,0,0,1,1,0,1,0,0
10,8,589,15947,20000,1,0,0,1,1,0,1,0,0
10,8,590,15948,20000,1,0,0,1,1,0,1,0,0
10,8,591,15949,20000,1,0,0,1,1,0,1,0,0
10,8,592,15950,20000,1,0,0,1,1,0,1,0,0
10,8,593,15951,20000,1,0,0,1,1,0,1,0,0
10,8,594,15952,20000,1,0,0,1,1,0,1,0,0
10,8,595,15953,20000,1,0,0,1,1,0,1,0,0
10,8,596,15954,20000,1,0,0,1,1,0,1,0,0
10,8,597,15955,20000,1,0,0,1,1,0,1,0,0
10,8,598,15956,20000,1,0,0,1,1,0,1,0,0
10,8,599,15957,20000,1,0,0,1,1,0,1,0,0
10,8,600,15958,20000,1,0,0,1,1,0,1,0,0
10,8,601,15959,20000,1,0,0,1,1,0,1,0,0
10,8,602,15960,20000,1,0,0,1,1,0,1,0,0
10,8,603,15961,20000,1,0,0,1,1,0,1,0,0
10,8,604,15962,20000,1,0,0,1,1,0,1,0,0
10,8,605,15963,20000,1,0,0,1,1,0,1,0,0
10,8,606,15964,20000,1,0,0,1,1,0,1,0,0
10,8,607,15965,20000,1,0,0,1,1,0,1,0,0
10,8,608,15966,20000,1,0,0,1,1,0,1,0,0
10,8,609,15967,20000,1,0,0,1,1,0,1,0,0
10,8,610,15968,20000,1,0,0,1,1,0,1,0,0
10,7,611,13506,250,1,0,0,1,1,0,1,50,0
10,7,612,15011,250,1,0,0,1,1,0,1,50,0
10,7,613,13636,250,1,0,0,1,1,0,1,50,0
10,7,614,1227,250,1,0,0,1,1,0,1,50,0
10,7,615,15022,250,1,0,0,1,1,0,1,50,0
10,8,616,4407,1000,1,0,0,1,1,0,1,0,0
10,8,617,4408,1000,1,0,0,1,1,0,1,0,0
10,8,618,4409,1000,1,0,0,1,1,0,1,0,0
10,8,619,4410,1000,1,0,0,1,1,0,1,0,0
10,8,620,4411,1000,1,0,0,1,1,0,1,0,0
10,8,621,4412,1000,1,0,0,1,1,0,1,0,0
10,8,622,4413,1000,1,0,0,1,1,0,1,0,0
10,8,623,4414,1000,1,0,0,1,1,0,1,0,0
10,8,624,4823,1000,1,0,0,1,1,0,1,0,0
10,8,625,4824,1000,1,0,0,1,1,0,1,0,0
10,8,626,4825,1000,1,0,0,1,1,0,1,0,0
10,8,627,4826,1000,1,0,0,1,1,0,1,0,0
10,8,628,4827,1000,1,0,0,1,1,0,1,0,0
10,8,629,4828,1000,1,0,0,1,1,0,1,0,0
10,8,630,4829,1000,1,0,0,1,1,0,1,0,0
10,8,631,4830,1000,1,0,0,1,1,0,1,0,0
10,8,632,5194,1000,1,0,0,1,1,0,1,0,0
10,8,633,5195,1000,1,0,0,1,1,0,1,0,0
10,8,634,5196,1000,1,0,0,1,1,0,1,0,0
10,8,635,5197,1000,1,0,0,1,1,0,1,0,0
10,8,636,5198,1000,1,0,0,1,1,0,1,0,0
10,8,637,5199,1000,1,0,0,1,1,0,1,0,0
10,8,638,5200,1000,1,0,0,1,1,0,1,0,0
10,8,639,5201,1000,1,0,0,1,1,0,1,0,0
10,8,640,13630,1000,1,0,0,1,1,0,1,0,0
10,8,641,13631,1000,1,0,0,1,1,0,1,0,0
10,8,642,13632,1000,1,0,0,1,1,0,1,0,0
10,8,643,13633,1000,1,0,0,1,1,0,1,0,0
10,8,644,13634,1000,1,0,0,1,1,0,1,0,0
10,8,645,13635,1000,1,0,0,1,1,0,1,0,0
10,8,646,15103,1000,1,0,0,1,1,0,1,0,0
10,8,647,15104,1000,1,0,0,1,1,0,1,0,0
10,8,648,15105,1000,1,0,0,1,1,0,1,0,0
10,8,649,15106,1000,1,0,0,1,1,0,1,0,0
10,8,650,15107,1000,1,0,0,1,1,0,1,0,0
10,8,651,15108,1000,1,0,0,1,1,0,1,0,0
10,8,652,16459,1000,1,0,0,1,1,0,1,0,0
10,8,653,16460,1000,1,0,0,1,1,0,1,0,0
10,8,654,16461,1000,1,0,0,1,1,0,1,0,0
10,8,655,16462,1000,1,0,0,1,1,0,1,0,0
10,8,656,16463,1000,1,0,0,1,1,0,1,0,0
10,8,657,16464,1000,1,0,0,1,1,0,1,0,0
10,8,658,16465,1000,1,0,0,1,1,0,1,0,0
10,8,659,16466,1000,1,0,0,1,1,0,1,0,0
10,8,660,16467,1000,1,0,0,1,1,0,1,0,0
10,8,661,16468,1000,1,0,0,1,1,0,1,0,0
10,8,662,16469,1000,1,0,0,1,1,0,1,0,0
10,8,663,16470,1000,1,0,0,1,1,0,1,0,0
10,8,664,16471,1000,1,0,0,1,1,0,1,0,0
10,8,665,16472,1000,1,0,0,1,1,0,1,0,0
10,8,666,13416,1000,1,0,0,1,1,0,1,0,0
10,8,667,13417,1000,1,0,0,1,1,0,1,0,0
10,8,668,13418,1000,1,0,0,1,1,0,1,0,0
10,8,669,13419,1000,1,0,0,1,1,0,1,0,0
10,8,670,13420,1000,1,0,0,1,1,0,1,0,0
10,8,671,14283,1000,1,0,0,1,1,0,1,0,0
10,8,672,14284,1000,1,0,0,1,1,0,1,0,0
10,8,673,14285,1000,1,0,0,1,1,0,1,0,0
10,8,674,14286,1000,1,0,0,1,1,0,1,0,0
10,8,675,13182,1000,1,0,0,1,1,0,1,0,0
10,8,676,13507,1000,1,0,0,1,1,0,1,0,0
10,8,677,13981,1000,1,0,0,1,1,0,1,0,0
10,8,678,14744,1000,1,0,0,1,1,0,1,0,0
10,8,679,14893,1000,1,0,0,1,1,0,1,0,0
10,8,680,15785,1000,1,0,0,1,1,0,1,0,0
10,8,681,16419,1000,1,0,0,1,1,0,1,0,0
10,8,682,11470,1000,1,0,0,1,1,0,1,0,0
10,8,683,12512,1000,1,0,0,1,1,0,1,0,0
10,8,684,12884,1000,1,0,0,1,1,0,1,0,0
10,8,685,12513,1000,1,0,0,1,1,0,1,0,0
10,8,686,12514,1000,1,0,0,1,1,0,1,0,0
10,8,687,12515,1000,1,0,0,1,1,0,1,0,0
10,8,688,12516,1000,1,0,0,1,1,0,1,0,0
10,8,689,12517,1000,1,0,0,1,1,0,1,0,0
10,8,690,12518,1000,1,0,0,1,1,0,1,0,0
10,8,691,12519,1000,1,0,0,1,1,0,1,0,0
10,8,692,12520,1000,1,0,0,1,1,0,1,0,0
10,8,693,12521,1000,1,0,0,1,1,0,1,0,0
10,8,694,8179,1000,1,0,0,1,1,0,1,0,0
10,8,695,9704,1000,1,0,0,1,1,0,1,0,0
10,8,696,15448,1000,1,0,0,1,1,0,1,0,0
10,8,697,11162,1000,1,0,0,1,1,0,1,0,0
10,8,698,11163,1000,1,0,0,1,1,0,1,0,0
10,8,699,11164,1000,1,0,0,1,1,0,1,0,0
10,8,700,11165,1000,1,0,0,1,1,0,1,0,0
10,8,701,11661,1000,1,0,0,1,1,0,1,0,0
10,8,702,11662,1000,1,0,0,1,1,0,1,0,0
10,8,703,14639,1000,1,0,0,1,1,0,1,0,0
10,8,704,13607,10,1,0,0,1,1,0,1,0,0
10,7,705,15774,3000,1,0,0,1,1,0,1,100,0
10,7,706,15775,3000,1,0,0,1,1,0,1,100,0
10,7,707,11420,3000,1,0,0,1,1,0,1,100,0
10,7,708,14704,3000,1,0,0,1,1,0,1,100,0
10,7,709,13177,3000,1,0,0,1,1,0,1,100,0
10,7,710,14191,3000,1,0,0,1,1,0,1,100,0
10,7,711,13449,3000,1,0,0,1,1,0,1,100,0
10,7,712,14192,3000,1,0,0,1,1,0,1,100,0
10,7,713,15772,3000,1,0,0,1,1,0,1,100,0
10,7,714,13791,3000,1,0,0,1,1,0,1,100,0
10,7,715,14006,3000,1,0,0,1,1,0,1,100,0
10,7,716,15768,3000,1,0,0,1,1,0,1,100,0
10,7,717,14069,3000,1,0,0,1,1,0,1,100,0
10,7,718,14124,3000,1,0,0,1,1,0,1,100,0
10,7,719,15507,3000,1,0,0,1,1,0,1,100,0
10,7,720,15508,3000,1,0,0,1,1,0,1,100,0
10,7,721,14855,3000,1,0,0,1,1,0,1,100,0
10,7,722,14894,3000,1,0,0,1,1,0,1,100,0
10,7,723,16444,3000,1,0,0,1,1,0,1,100,0
10,7,724,16445,3000,1,0,0,1,1,0,1,100,0
10,7,725,12509,3000,1,0,0,1,1,0,1,100,0
10,7,726,14126,3000,1,0,0,1,1,0,1,100,0
10,7,727,15062,3000,1,0,0,1,1,0,1,100,0
10,7,728,15063,3000,1,0,0,1,1,0,1,100,0
10,7,729,14891,3000,1,0,0,1,1,0,1,100,0
10,7,730,14895,3000,1,0,0,1,1,0,1,100,0
10,7,731,14091,3000,1,0,0,1,1,0,1,100,0
10,7,732,14092,3000,1,0,0,1,1,0,1,100,0
10,7,733,14501,3000,1,0,0,1,1,0,1,100,0
10,7,734,14506,3000,1,0,0,1,1,0,1,100,0
10,7,735,15285,3000,1,0,0,1,1,0,1,100,0
10,7,736,15286,3000,1,0,0,1,1,0,1,100,0
10,7,737,16442,3000,1,0,0,1,1,0,1,100,0
10,7,738,16443,3000,1,0,0,1,1,0,1,100,0
10,7,739,15027,3000,1,0,0,1,1,0,1,100,0
10,7,740,15028,3000,1,0,0,1,1,0,1,100,0
10,7,741,13453,3000,1,0,0,1,1,0,1,100,0
10,7,742,14193,3000,1,0,0,1,1,0,1,100,0
10,7,743,13178,3000,1,0,0,1,1,0,1,100,0
10,7,744,14194,3000,1,0,0,1,1,0,1,100,0
10,7,745,16454,3000,1,0,0,1,1,0,1,100,0
10,7,746,16455,3000,1,0,0,1,1,0,1,100,0
10,7,747,15030,3000,1,0,0,1,1,0,1,100,0
10,7,748,15031,3000,1,0,0,1,1,0,1,100,0
10,7,749,13790,3000,1,0,0,1,1,0,1,100,0
10,7,750,14005,3000,1,0,0,1,1,0,1,100,0
10,7,751,14406,3000,1,0,0,1,1,0,1,100,0
10,7,752,14413,3000,1,0,0,1,1,0,1,100,0
10,7,753,16448,3000,1,0,0,1,1,0,1,100,0
10,7,754,16449,3000,1,0,0,1,1,0,1,100,0
10,7,755,12872,3000,1,0,0,1,1,0,1,100,0
10,7,756,14187,3000,1,0,0,1,1,0,1,100,0
10,7,757,14125,3000,1,0,0,1,1,0,1,100,0
10,7,758,14500,3000,1,0,0,1,1,0,1,100,0
10,7,759,14505,3000,1,0,0,1,1,0,1,100,0
10,7,760,15118,3000,1,0,0,1,1,0,1,100,0
10,7,761,15119,3000,1,0,0,1,1,0,1,100,0
10,7,762,14662,3000,1,0,0,1,1,0,1,100,0
10,7,763,14663,3000,1,0,0,1,1,0,1,100,0
10,7,764,15771,3000,1,0,0,1,1,0,1,100,0
10,7,765,9700,3000,1,0,0,1,1,0,1,100,0
10,7,766,14498,3000,1,0,0,1,1,0,1,100,0
10,7,767,14913,3000,1,0,0,1,1,0,1,100,0
10,7,768,14914,3000,1,0,0,1,1,0,1,100,0
10,7,769,13508,3000,1,0,0,1,1,0,1,100,0
10,7,770,15115,3000,1,0,0,1,1,0,1,100,0
10,7,771,15116,3000,1,0,0,1,1,0,1,100,0
10,7,772,15113,3000,1,0,0,1,1,0,1,100,0
10,7,773,15114,3000,1,0,0,1,1,0,1,100,0
10,7,774,15222,3000,1,0,0,1,1,0,1,100,0
10,7,775,15223,3000,1,0,0,1,1,0,1,100,0
10,7,776,10750,3000,1,0,0,1,1,0,1,100,0
10,7,777,14705,3000,1,0,0,1,1,0,1,100,0
10,7,778,15027,3000,1,0,0,1,1,0,1,100,0
10,7,779,15028,3000,1,0,0,1,1,0,1,100,0
10,7,780,10380,3000,1,0,0,1,1,0,1,100,0
10,7,781,15060,3000,1,0,0,1,1,0,1,100,0
10,7,782,13963,3000,1,0,0,1,1,0,1,100,0
10,7,783,14026,3000,1,0,0,1,1,0,1,100,0
10,7,784,13964,3000,1,0,0,1,1,0,1,100,0
10,7,785,14027,3000,1,0,0,1,1,0,1,100,0
10,7,786,15064,3000,1,0,0,1,1,0,1,100,0
10,7,787,15065,3000,1,0,0,1,1,0,1,100,0
10,7,788,15524,3000,1,0,0,1,1,0,1,100,0
10,7,789,15525,3000,1,0,0,1,1,0,1,100,0
10,7,790,16450,3000,1,0,0,1,1,0,1,100,0
10,7,791,16451,3000,1,0,0,1,1,0,1,100,0
10,7,792,16344,3000,1,0,0,1,1,0,1,100,0
10,7,793,16345,3000,1,0,0,1,1,0,1,100,0
10,7,794,16342,3000,1,0,0,1,1,0,1,100,0
10,7,795,16343,3000,1,0,0,1,1,0,1,100,0
10,7,796,15220,3000,1,0,0,1,1,0,1,100,0
10,7,797,15221,3000,1,0,0,1,1,0,1,100,0
10,7,798,15066,3000,1,0,0,1,1,0,1,100,0
10,7,799,15067,3000,1,0,0,1,1,0,1,100,0
10,7,800,14089,3000,1,0,0,1,1,0,1,100,0
10,7,801,14090,3000,1,0,0,1,1,0,1,100,0
10,7,802,14195,3000,1,0,0,1,1,0,1,100,0
10,7,803,14196,3000,1,0,0,1,1,0,1,100,0
10,7,804,13965,3000,1,0,0,1,1,0,1,100,0
10,7,805,14028,3000,1,0,0,1,1,0,1,100,0
10,7,806,13508,3000,1,0,0,1,1,0,1,100,0
10,7,807,13962,3000,1,0,0,1,1,0,1,100,0
10,7,808,14314,3000,1,0,0,1,1,0,1,100,0
10,7,809,13404,3000,1,0,0,1,1,0,1,100,0
10,7,810,14188,3000,1,0,0,1,1,0,1,100,0
10,7,811,14032,3000,1,0,0,1,1,0,1,100,0
10,7,812,13960,3000,1,0,0,1,1,0,1,100,0
10,7,813,15819,3000,1,0,0,1,1,0,1,100,0
10,7,814,15820,3000,1,0,0,1,1,0,1,100,0
10,7,815,10750,3000,1,0,0,1,1,0,1,100,0
10,7,816,14705,3000,1,0,0,1,1,0,1,100,0
10,7,817,14407,3000,1,0,0,1,1,0,1,100,0
10,7,818,14414,3000,1,0,0,1,1,0,1,100,0
10,7,819,16352,3000,1,0,0,1,1,0,1,100,0
10,7,820,16353,3000,1,0,0,1,1,0,1,100,0
10,7,821,14502,3000,1,0,0,1,1,0,1,100,0
10,7,822,14507,3000,1,0,0,1,1,0,1,100,0
10,7,823,10811,3000,1,0,0,1,1,0,1,100,0
10,7,824,15061,3000,1,0,0,1,1,0,1,100,0
10,7,825,15823,3000,1,0,0,1,1,0,1,100,0
10,7,826,15824,3000,1,0,0,1,1,0,1,100,0
10,7,827,15224,3000,1,0,0,1,1,0,1,100,0
10,7,828,15225,3000,1,0,0,1,1,0,1,100,0
10,7,829,14503,3000,1,0,0,1,1,0,1,100,0
10,7,830,14510,3000,1,0,0,1,1,0,1,100,0
10,7,831,15776,3000,1,0,0,1,1,0,1,100,0
10,7,832,15777,3000,1,0,0,1,1,0,1,100,0
10,7,833,15821,3000,1,0,0,1,1,0,1,100,0
10,7,834,15822,3000,1,0,0,1,1,0,1,100,0
10,7,835,14198,3000,1,0,0,1,1,0,1,100,0
10,7,836,14197,3000,1,0,0,1,1,0,1,100,0
10,7,837,16446,3000,1,0,0,1,1,0,1,100,0
10,7,838,16447,3000,1,0,0,1,1,0,1,100,0
10,7,839,14905,3000,1,0,0,1,1,0,1,100,0
10,7,840,14907,3000,1,0,0,1,1,0,1,100,0
10,7,841,14904,3000,1,0,0,1,1,0,1,100,0
10,7,842,14906,3000,1,0,0,1,1,0,1,100,0
10,7,843,14659,3000,1,0,0,1,1,0,1,100,0
10,7,844,14660,3000,1,0,0,1,1,0,1,100,0
10,7,845,13326,3000,1,0,0,1,1,0,1,100,0
10,7,846,14416,3000,1,0,0,1,1,0,1,100,0
10,7,847,13450,3000,1,0,0,1,1,0,1,100,0
10,7,848,14031,3000,1,0,0,1,1,0,1,100,0
10,7,849,16492,3000,1,0,0,1,1,0,1,100,0
10,7,850,16493,3000,1,0,0,1,1,0,1,100,0
10,8,851,1520,1,1,0,0,1,1,0,1,0,0
10,8,852,7011,1,1,0,0,1,1,0,1,0,0
10,7,853,14299,500,1,0,0,1,1,0,1,20,0
10,7,854,14389,500,1,0,0,1,1,0,1,20,0
10,7,855,15177,500,1,0,0,1,1,0,1,20,0
10,7,856,14537,500,1,0,0,1,1,0,1,20,0
10,7,857,14758,500,1,0,0,1,1,0,1,20,0
10,7,858,14854,500,1,0,0,1,1,0,1,20,0
10,7,859,13974,500,1,0,0,1,1,0,1,20,0
10,7,860,15021,500,1,0,0,1,1,0,1,20,0
10,7,861,15111,500,1,0,0,1,1,0,1,20,0
10,7,862,15226,500,1,0,0,1,1,0,1,20,0
10,7,863,15773,500,1,0,0,1,1,0,1,20,0
10,7,864,15825,500,1,0,0,1,1,0,1,20,0
10,7,865,15827,500,1,0,0,1,1,0,1,20,0
10,7,866,16340,500,1,0,0,1,1,0,1,20,0
10,7,867,16341,500,1,0,0,1,1,0,1,20,0
10,7,868,16457,500,1,0,0,1,1,0,1,20,0
10,7,869,16458,500,1,0,0,1,1,0,1,20,0
10,7,870,11698,250,1,0,0,1,1,0,1,50,0
10,7,871,11700,250,1,0,0,1,1,0,1,50,0
10,8,872,4358,10,1,0,0,1,1,0,1,0,0
10,8,873,7981,1,1,0,0,1,1,0,1,0,0
10,8,874,7267,20,1,0,0,1,1,0,1,0,0
10,8,875,9958,20,1,0,0,1,1,0,1,0,999
10,8,876,1548,20,1,0,0,1,1,0,1,0,0
10,8,877,1613,20,1,0,0,1,1,0,1,0,0
10,8,878,1026,1,1,0,0,1,1,0,1,0,0
10,8,879,5380,1,1,0,0,1,1,0,1,0,0
10,8,880,11284,15,1,0,0,1,1,0,1,0,0
10,8,881,11285,15,1,0,0,1,1,0,1,0,0
10,8,882,11286,15,1,0,0,1,1,0,1,0,0
10,8,883,10356,500,1,0,0,1,1,0,1,0,0
10,8,884,12511,500,1,0,0,1,1,0,1,0,0
10,8,885,13238,500,1,0,0,1,1,0,1,0,0
10,8,886,1691,1,1,0,0,1,1,0,1,0,0
10,8,887,9708,1,1,0,0,1,1,0,1,0,0
10,8,888,11383,10,1,0,0,1,1,0,1,0,0
10,8,889,11382,10,1,0,0,1,1,0,1,0,0
10,8,890,11381,10,1,0,0,1,1,0,1,0,0
10,7,891,16348,3000,1,0,0,1,1,0,1,100,0
10,8,892,11386,10,1,0,0,1,1,0,1,0,0
10,8,893,5767,1,10000,0,0,1,1,0,1,0,0
10,8,894,5765,1,10000,0,0,1,1,0,1,0,0
10,8,895,5768,1,10000,0,0,1,1,0,1,0,0
10,8,896,14444,10,1,0,0,1,1,0,1,0,0
10,8,897,14443,10,1,0,0,1,1,0,1,0,0
10,8,898,14445,10,1,0,0,1,1,0,1,0,0
10,8,899,15068,500,1,0,0,1,1,0,1,20,0
10,7,900,16532,1000,1,0,0,1,1,0,1,0,0
10,8,901,100,1,10000,0,0,1,1,0,1,0,0
10,8,902,11243,1,1,0,0,1,1,0,1,0,0
10,8,903,101,1,10000,0,0,1,1,0,1,0,0
10,7,904,14368,3000,1,0,0,1,1,0,1,50,0
10,8,905,8943,1,20,0,0,1,1,0,1,0,0
10,7,906,1622,3000,1,0,0,1,1,0,1,0,0
10,8,907,8953,1,20,0,0,1,1,0,1,0,0
10,8,908,13693,1,20,0,0,1,1,0,1,0,0
10,8,909,8949,1,20,0,0,1,1,0,1,0,0
10,8,910,8955,1,20,0,0,1,1,0,1,0,0
10,7,911,16456,500,1,0,0,1,1,0,1,0,0
1 10 6 1 2146 25 1 0 0 1 1 0 1 0 0
2 10 6 2 2147 25 1 0 0 1 1 0 1 0 0
3 10 6 3 2148 25 1 0 0 1 1 0 1 0 0
4 10 6 4 2149 25 1 0 0 1 1 0 1 0 0
5 10 6 5 2150 25 1 0 0 1 1 0 1 0 0
6 10 6 6 2151 25 1 0 0 1 1 0 1 0 0
7 10 6 7 2152 25 1 0 0 1 1 0 1 0 0
8 10 6 8 2153 25 1 0 0 1 1 0 1 0 0
9 10 6 9 2154 25 1 0 0 1 1 0 1 0 0
10 10 6 10 2155 25 1 0 0 1 1 0 1 0 0
11 10 6 11 4398 25 1 0 0 1 1 0 1 0 0
12 10 6 12 12460 25 1 0 0 1 1 0 1 0 0
13 10 6 13 12461 25 1 0 0 1 1 0 1 0 0
14 10 6 14 12462 25 1 0 0 1 1 0 1 0 0
15 10 6 15 12463 25 1 0 0 1 1 0 1 0 0
16 10 6 16 12464 25 1 0 0 1 1 0 1 0 0
17 10 6 17 12465 25 1 0 0 1 1 0 1 0 0
18 10 6 18 12466 25 1 0 0 1 1 0 1 0 0
19 10 6 19 12467 25 1 0 0 1 1 0 1 0 0
20 10 6 20 12468 25 1 0 0 1 1 0 1 0 0
21 10 6 21 12469 25 1 0 0 1 1 0 1 0 0
22 10 6 22 15109 1000 1 0 0 1 1 0 1 0 0
23 10 6 23 15110 1000 1 0 0 1 1 0 1 0 0
24 10 6 24 2158 200 100 0 0 1 1 0 1 0 0
25 10 6 25 12306 2 1 0 0 1 1 0 1 80 0
26 10 6 26 12306 20000 10000 0 0 1 1 0 1 80 0
27 10 4 27 11664 20000 1 0 0 1 1 0 1 0 0
28 10 4 28 11665 20000 1 0 0 1 1 0 1 0 0
29 10 4 29 11666 20000 1 0 0 1 1 0 1 0 0
30 10 4 30 11667 20000 1 0 0 1 1 0 1 0 0
31 10 4 31 11668 20000 1 0 0 1 1 0 1 0 0
32 10 4 32 11669 20000 1 0 0 1 1 0 1 0 0
33 10 4 33 11670 20000 1 0 0 1 1 0 1 0 0
34 10 4 34 11671 20000 1 0 0 1 1 0 1 0 0
35 10 4 35 11672 20000 1 0 0 1 1 0 1 0 0
36 10 4 36 11673 20000 1 0 0 1 1 0 1 0 0
37 10 4 37 11674 20000 1 0 0 1 1 0 1 0 0
38 10 4 38 11675 20000 1 0 0 1 1 0 1 0 0
39 10 4 39 11676 20000 1 0 0 1 1 0 1 0 0
40 10 4 40 11677 20000 1 0 0 1 1 0 1 0 0
41 10 4 41 11678 20000 1 0 0 1 1 0 1 0 0
42 10 4 42 11679 20000 1 0 0 1 1 0 1 0 0
43 10 4 43 11680 20000 1 0 0 1 1 0 1 0 0
44 10 4 44 11681 20000 1 0 0 1 1 0 1 0 0
45 10 4 45 11682 20000 1 0 0 1 1 0 1 0 0
46 10 4 46 11683 20000 1 0 0 1 1 0 1 0 0
47 10 4 47 11684 20000 1 0 0 1 1 0 1 0 0
48 10 4 48 11685 20000 1 0 0 1 1 0 1 0 0
49 10 4 49 11686 20000 1 0 0 1 1 0 1 0 0
50 10 4 50 11687 20000 1 0 0 1 1 0 1 0 0
51 10 4 51 11688 20000 1 0 0 1 1 0 1 0 0
52 10 4 52 11689 20000 1 0 0 1 1 0 1 0 0
53 10 4 53 11690 20000 1 0 0 1 1 0 1 0 0
54 10 4 54 11691 20000 1 0 0 1 1 0 1 0 0
55 10 4 55 11692 20000 1 0 0 1 1 0 1 0 0
56 10 4 56 11693 20000 1 0 0 1 1 0 1 0 0
57 10 4 57 11694 20000 1 0 0 1 1 0 1 0 0
58 10 4 58 11695 20000 1 0 0 1 1 0 1 0 0
59 10 4 59 11696 20000 1 0 0 1 1 0 1 0 0
60 10 4 60 11697 20000 1 0 0 1 1 0 1 0 0
61 10 4 61 12893 20000 1 0 0 1 1 0 1 0 0
62 10 4 62 12894 20000 1 0 0 1 1 0 1 0 0
63 10 4 63 12895 20000 1 0 0 1 1 0 1 0 0
64 10 4 64 12896 20000 1 0 0 1 1 0 1 0 0
65 10 4 65 12897 20000 1 0 0 1 1 0 1 0 0
66 10 4 66 12898 20000 1 0 0 1 1 0 1 0 0
67 10 4 67 12899 20000 1 0 0 1 1 0 1 0 0
68 10 4 68 14337 20000 1 0 0 1 1 0 1 0 0
69 10 4 69 14338 20000 1 0 0 1 1 0 1 0 0
70 10 4 70 14339 20000 1 0 0 1 1 0 1 0 0
71 10 4 71 14340 20000 1 0 0 1 1 0 1 0 0
72 10 4 72 14341 20000 1 0 0 1 1 0 1 0 0
73 10 4 73 14342 20000 1 0 0 1 1 0 1 0 0
74 10 4 74 14343 20000 1 0 0 1 1 0 1 0 0
75 10 4 75 14344 20000 1 0 0 1 1 0 1 0 0
76 10 4 76 14345 20000 1 0 0 1 1 0 1 0 0
77 10 4 77 9254 10000 1 0 0 1 1 0 1 0 0
78 10 4 78 9255 10000 1 0 0 1 1 0 1 0 0
79 10 4 79 9256 10000 1 0 0 1 1 0 1 0 0
80 10 4 80 9257 10000 1 0 0 1 1 0 1 0 0
81 10 4 81 9258 10000 1 0 0 1 1 0 1 0 0
82 10 4 82 9259 10000 1 0 0 1 1 0 1 0 0
83 10 4 83 9260 10000 1 0 0 1 1 0 1 0 0
84 10 4 84 9261 10000 1 0 0 1 1 0 1 0 0
85 10 4 85 9262 10000 1 0 0 1 1 0 1 0 0
86 10 4 86 9263 10000 1 0 0 1 1 0 1 0 0
87 10 4 87 9264 10000 1 0 0 1 1 0 1 0 0
88 10 4 88 9265 10000 1 0 0 1 1 0 1 0 0
89 10 4 89 9266 10000 1 0 0 1 1 0 1 0 0
90 10 4 90 9267 10000 1 0 0 1 1 0 1 0 0
91 10 4 91 9268 10000 1 0 0 1 1 0 1 0 0
92 10 4 92 9269 10000 1 0 0 1 1 0 1 0 0
93 10 4 93 9270 10000 1 0 0 1 1 0 1 0 0
94 10 4 94 9271 10000 1 0 0 1 1 0 1 0 0
95 10 4 95 9272 10000 1 0 0 1 1 0 1 0 0
96 10 4 96 9273 10000 1 0 0 1 1 0 1 0 0
97 10 4 97 9274 10000 1 0 0 1 1 0 1 0 0
98 10 4 98 9275 10000 1 0 0 1 1 0 1 0 0
99 10 4 99 9276 10000 1 0 0 1 1 0 1 0 0
100 10 4 100 9277 10000 1 0 0 1 1 0 1 0 0
101 10 4 101 9278 10000 1 0 0 1 1 0 1 0 0
102 10 4 102 9279 10000 1 0 0 1 1 0 1 0 0
103 10 4 103 9280 10000 1 0 0 1 1 0 1 0 0
104 10 4 104 9281 10000 1 0 0 1 1 0 1 0 0
105 10 4 105 9282 10000 1 0 0 1 1 0 1 0 0
106 10 4 106 9283 10000 1 0 0 1 1 0 1 0 0
107 10 4 107 9284 10000 1 0 0 1 1 0 1 0 0
108 10 4 108 9285 10000 1 0 0 1 1 0 1 0 0
109 10 4 109 9286 10000 1 0 0 1 1 0 1 0 0
110 10 4 110 9287 10000 1 0 0 1 1 0 1 0 0
111 10 4 111 9288 10000 1 0 0 1 1 0 1 0 0
112 10 4 112 9289 10000 1 0 0 1 1 0 1 0 0
113 10 4 113 9290 10000 1 0 0 1 1 0 1 0 0
114 10 4 114 9291 10000 1 0 0 1 1 0 1 0 0
115 10 4 115 9292 10000 1 0 0 1 1 0 1 0 0
116 10 4 116 9293 10000 1 0 0 1 1 0 1 0 0
117 10 4 117 9294 10000 1 0 0 1 1 0 1 0 0
118 10 4 118 9295 10000 1 0 0 1 1 0 1 0 0
119 10 4 119 9296 10000 1 0 0 1 1 0 1 0 0
120 10 4 120 9297 10000 1 0 0 1 1 0 1 0 0
121 10 4 121 9298 10000 1 0 0 1 1 0 1 0 0
122 10 4 122 9299 10000 1 0 0 1 1 0 1 0 0
123 10 4 123 9300 10000 1 0 0 1 1 0 1 0 0
124 10 4 124 9301 10000 1 0 0 1 1 0 1 0 0
125 10 4 125 13196 10000 1 0 0 1 1 0 1 0 0
126 10 4 126 13197 10000 1 0 0 1 1 0 1 0 0
127 10 4 127 13198 10000 1 0 0 1 1 0 1 0 0
128 10 4 128 13199 10000 1 0 0 1 1 0 1 0 0
129 10 4 129 15542 10000 1 0 0 1 1 0 1 0 0
130 10 4 130 15543 10000 1 0 0 1 1 0 1 0 0
131 10 4 131 15544 10000 1 0 0 1 1 0 1 0 0
132 10 4 132 15545 10000 1 0 0 1 1 0 1 0 0
133 10 4 133 13640 20000 1 0 0 1 1 0 1 0 0
134 10 4 134 13641 20000 1 0 0 1 1 0 1 0 0
135 10 4 135 13642 20000 1 0 0 1 1 0 1 0 0
136 10 4 136 13643 20000 1 0 0 1 1 0 1 0 0
137 10 4 137 13644 20000 1 0 0 1 1 0 1 0 0
138 10 4 138 13645 20000 1 0 0 1 1 0 1 0 0
139 10 4 139 13646 20000 1 0 0 1 1 0 1 0 0
140 10 4 140 13647 20000 1 0 0 1 1 0 1 0 0
141 10 4 141 13648 20000 1 0 0 1 1 0 1 0 0
142 10 4 142 13649 20000 1 0 0 1 1 0 1 0 0
143 10 4 143 13650 20000 1 0 0 1 1 0 1 0 0
144 10 4 144 13651 20000 1 0 0 1 1 0 1 0 0
145 10 4 145 13652 20000 1 0 0 1 1 0 1 0 0
146 10 4 146 13653 20000 1 0 0 1 1 0 1 0 0
147 10 4 147 13654 20000 1 0 0 1 1 0 1 0 0
148 10 4 148 13655 20000 1 0 0 1 1 0 1 0 0
149 10 4 149 13656 20000 1 0 0 1 1 0 1 0 0
150 10 4 150 13657 20000 1 0 0 1 1 0 1 0 0
151 10 4 151 13658 20000 1 0 0 1 1 0 1 0 0
152 10 4 152 13659 20000 1 0 0 1 1 0 1 0 0
153 10 4 153 13660 20000 1 0 0 1 1 0 1 0 0
154 10 4 154 13661 20000 1 0 0 1 1 0 1 0 0
155 10 4 155 13662 20000 1 0 0 1 1 0 1 0 0
156 10 4 156 13663 20000 1 0 0 1 1 0 1 0 0
157 10 4 157 13664 20000 1 0 0 1 1 0 1 0 0
158 10 4 158 13665 20000 1 0 0 1 1 0 1 0 0
159 10 4 159 13666 20000 1 0 0 1 1 0 1 0 0
160 10 4 160 13667 20000 1 0 0 1 1 0 1 0 0
161 10 4 161 13668 20000 1 0 0 1 1 0 1 0 0
162 10 4 162 13669 20000 1 0 0 1 1 0 1 0 0
163 10 4 163 13670 20000 1 0 0 1 1 0 1 0 0
164 10 4 164 13671 20000 1 0 0 1 1 0 1 0 0
165 10 4 165 13672 20000 1 0 0 1 1 0 1 0 0
166 10 4 166 13673 20000 1 0 0 1 1 0 1 0 0
167 10 4 167 13674 20000 1 0 0 1 1 0 1 0 0
168 10 4 168 13675 20000 1 0 0 1 1 0 1 0 0
169 10 4 169 13676 20000 1 0 0 1 1 0 1 0 0
170 10 4 170 13677 20000 1 0 0 1 1 0 1 0 0
171 10 4 171 13678 20000 1 0 0 1 1 0 1 0 0
172 10 4 172 13679 20000 1 0 0 1 1 0 1 0 0
173 10 4 173 13680 20000 1 0 0 1 1 0 1 0 0
174 10 4 174 13681 20000 1 0 0 1 1 0 1 0 0
175 10 4 175 13682 20000 1 0 0 1 1 0 1 0 0
176 10 4 176 13683 20000 1 0 0 1 1 0 1 0 0
177 10 4 177 13684 20000 1 0 0 1 1 0 1 0 0
178 10 4 178 13685 20000 1 0 0 1 1 0 1 0 0
179 10 4 179 13686 20000 1 0 0 1 1 0 1 0 0
180 10 4 180 13687 20000 1 0 0 1 1 0 1 0 0
181 10 4 181 13688 20000 1 0 0 1 1 0 1 0 0
182 10 4 182 13689 20000 1 0 0 1 1 0 1 0 0
183 10 4 183 13690 20000 1 0 0 1 1 0 1 0 0
184 10 4 184 13691 20000 1 0 0 1 1 0 1 0 0
185 10 4 185 15546 20000 1 0 0 1 1 0 1 0 0
186 10 4 186 15547 20000 1 0 0 1 1 0 1 0 0
187 10 4 187 15548 20000 1 0 0 1 1 0 1 0 0
188 10 4 188 15549 20000 1 0 0 1 1 0 1 0 0
189 10 4 189 16162 35000 1 0 0 1 1 0 1 0 0
190 10 4 190 16163 35000 1 0 0 1 1 0 1 0 0
191 10 4 191 16164 35000 1 0 0 1 1 0 1 0 0
192 10 4 192 16165 35000 1 0 0 1 1 0 1 0 0
193 10 4 193 16166 35000 1 0 0 1 1 0 1 0 0
194 10 4 194 16167 35000 1 0 0 1 1 0 1 0 0
195 10 4 195 16168 35000 1 0 0 1 1 0 1 0 0
196 10 4 196 16169 35000 1 0 0 1 1 0 1 0 0
197 10 4 197 16172 35000 1 0 0 1 1 0 1 0 0
198 10 4 198 16173 35000 1 0 0 1 1 0 1 0 0
199 10 4 199 16174 35000 1 0 0 1 1 0 1 0 0
200 10 4 200 16175 35000 1 0 0 1 1 0 1 0 0
201 10 4 201 16176 35000 1 0 0 1 1 0 1 0 0
202 10 4 202 16177 35000 1 0 0 1 1 0 1 0 0
203 10 4 203 16178 35000 1 0 0 1 1 0 1 0 0
204 10 4 204 16179 35000 1 0 0 1 1 0 1 0 0
205 10 4 205 16182 35000 1 0 0 1 1 0 1 0 0
206 10 4 206 16183 35000 1 0 0 1 1 0 1 0 0
207 10 4 207 16184 35000 1 0 0 1 1 0 1 0 0
208 10 4 208 16185 35000 1 0 0 1 1 0 1 0 0
209 10 4 209 16186 35000 1 0 0 1 1 0 1 0 0
210 10 4 210 16187 35000 1 0 0 1 1 0 1 0 0
211 10 4 211 16188 35000 1 0 0 1 1 0 1 0 0
212 10 4 212 16189 35000 1 0 0 1 1 0 1 0 0
213 10 4 213 16192 35000 1 0 0 1 1 0 1 0 0
214 10 4 214 16193 35000 1 0 0 1 1 0 1 0 0
215 10 4 215 16194 35000 1 0 0 1 1 0 1 0 0
216 10 4 216 16195 35000 1 0 0 1 1 0 1 0 0
217 10 4 217 16196 35000 1 0 0 1 1 0 1 0 0
218 10 4 218 16197 35000 1 0 0 1 1 0 1 0 0
219 10 4 219 16198 35000 1 0 0 1 1 0 1 0 0
220 10 4 220 16199 35000 1 0 0 1 1 0 1 0 0
221 10 4 221 16202 35000 1 0 0 1 1 0 1 0 0
222 10 4 222 16203 35000 1 0 0 1 1 0 1 0 0
223 10 4 223 16204 35000 1 0 0 1 1 0 1 0 0
224 10 4 224 16205 35000 1 0 0 1 1 0 1 0 0
225 10 4 225 16206 35000 1 0 0 1 1 0 1 0 0
226 10 4 226 16207 35000 1 0 0 1 1 0 1 0 0
227 10 4 227 16208 35000 1 0 0 1 1 0 1 0 0
228 10 4 228 16209 35000 1 0 0 1 1 0 1 0 0
229 10 4 229 16212 35000 1 0 0 1 1 0 1 0 0
230 10 4 230 16213 35000 1 0 0 1 1 0 1 0 0
231 10 4 231 16214 35000 1 0 0 1 1 0 1 0 0
232 10 4 232 16215 35000 1 0 0 1 1 0 1 0 0
233 10 4 233 16216 35000 1 0 0 1 1 0 1 0 0
234 10 4 234 16217 35000 1 0 0 1 1 0 1 0 0
235 10 4 235 16218 35000 1 0 0 1 1 0 1 0 0
236 10 4 236 16219 35000 1 0 0 1 1 0 1 0 0
237 10 4 237 16222 35000 1 0 0 1 1 0 1 0 0
238 10 4 238 16223 35000 1 0 0 1 1 0 1 0 0
239 10 4 239 16224 35000 1 0 0 1 1 0 1 0 0
240 10 4 240 16225 35000 1 0 0 1 1 0 1 0 0
241 10 4 241 16226 35000 1 0 0 1 1 0 1 0 0
242 10 4 242 16227 35000 1 0 0 1 1 0 1 0 0
243 10 4 243 16228 35000 1 0 0 1 1 0 1 0 0
244 10 4 244 16229 35000 1 0 0 1 1 0 1 0 0
245 10 4 245 16232 35000 1 0 0 1 1 0 1 0 0
246 10 4 246 16233 35000 1 0 0 1 1 0 1 0 0
247 10 4 247 16234 35000 1 0 0 1 1 0 1 0 0
248 10 4 248 16235 35000 1 0 0 1 1 0 1 0 0
249 10 4 249 16236 35000 1 0 0 1 1 0 1 0 0
250 10 4 250 16237 35000 1 0 0 1 1 0 1 0 0
251 10 4 251 16238 35000 1 0 0 1 1 0 1 0 0
252 10 4 252 16239 35000 1 0 0 1 1 0 1 0 0
253 10 4 253 16242 35000 1 0 0 1 1 0 1 0 0
254 10 4 254 16243 35000 1 0 0 1 1 0 1 0 0
255 10 4 255 16244 35000 1 0 0 1 1 0 1 0 0
256 10 4 256 16245 35000 1 0 0 1 1 0 1 0 0
257 10 4 257 16246 35000 1 0 0 1 1 0 1 0 0
258 10 4 258 16247 35000 1 0 0 1 1 0 1 0 0
259 10 4 259 16248 35000 1 0 0 1 1 0 1 0 0
260 10 4 260 16249 35000 1 0 0 1 1 0 1 0 0
261 10 4 261 16252 35000 1 0 0 1 1 0 1 0 0
262 10 4 262 16253 35000 1 0 0 1 1 0 1 0 0
263 10 4 263 16254 35000 1 0 0 1 1 0 1 0 0
264 10 4 264 16255 35000 1 0 0 1 1 0 1 0 0
265 10 4 265 16256 35000 1 0 0 1 1 0 1 0 0
266 10 4 266 16257 35000 1 0 0 1 1 0 1 0 0
267 10 4 267 16258 35000 1 0 0 1 1 0 1 0 0
268 10 4 268 16259 35000 1 0 0 1 1 0 1 0 0
269 10 4 269 16262 35000 1 0 0 1 1 0 1 0 0
270 10 4 270 16263 35000 1 0 0 1 1 0 1 0 0
271 10 4 271 16264 35000 1 0 0 1 1 0 1 0 0
272 10 4 272 16265 35000 1 0 0 1 1 0 1 0 0
273 10 4 273 16266 35000 1 0 0 1 1 0 1 0 0
274 10 4 274 16267 35000 1 0 0 1 1 0 1 0 0
275 10 4 275 16268 35000 1 0 0 1 1 0 1 0 0
276 10 4 276 16269 35000 1 0 0 1 1 0 1 0 0
277 10 4 277 16272 35000 1 0 0 1 1 0 1 0 0
278 10 4 278 16273 35000 1 0 0 1 1 0 1 0 0
279 10 4 279 16274 35000 1 0 0 1 1 0 1 0 0
280 10 4 280 16275 35000 1 0 0 1 1 0 1 0 0
281 10 4 281 16276 35000 1 0 0 1 1 0 1 0 0
282 10 4 282 16277 35000 1 0 0 1 1 0 1 0 0
283 10 4 283 16278 35000 1 0 0 1 1 0 1 0 0
284 10 4 284 16279 35000 1 0 0 1 1 0 1 0 0
285 10 4 285 16282 35000 1 0 0 1 1 0 1 0 0
286 10 4 286 16283 35000 1 0 0 1 1 0 1 0 0
287 10 4 287 16284 35000 1 0 0 1 1 0 1 0 0
288 10 4 288 16285 35000 1 0 0 1 1 0 1 0 0
289 10 4 289 16286 35000 1 0 0 1 1 0 1 0 0
290 10 4 290 16287 35000 1 0 0 1 1 0 1 0 0
291 10 4 291 16288 35000 1 0 0 1 1 0 1 0 0
292 10 4 292 16289 35000 1 0 0 1 1 0 1 0 0
293 10 4 293 16292 35000 1 0 0 1 1 0 1 0 0
294 10 4 294 16293 35000 1 0 0 1 1 0 1 0 0
295 10 4 295 16294 35000 1 0 0 1 1 0 1 0 0
296 10 4 296 16295 35000 1 0 0 1 1 0 1 0 0
297 10 4 297 16296 35000 1 0 0 1 1 0 1 0 0
298 10 4 298 16297 35000 1 0 0 1 1 0 1 0 0
299 10 4 299 16298 35000 1 0 0 1 1 0 1 0 0
300 10 4 300 16299 35000 1 0 0 1 1 0 1 0 0
301 10 8 301 14136 15000 1 0 0 1 1 0 1 0 0
302 10 8 302 14137 15000 1 0 0 1 1 0 1 0 0
303 10 8 303 14138 15000 1 0 0 1 1 0 1 0 0
304 10 8 304 14139 15000 1 0 0 1 1 0 1 0 0
305 10 8 305 14140 15000 1 0 0 1 1 0 1 0 0
306 10 8 306 14141 15000 1 0 0 1 1 0 1 0 0
307 10 8 307 14142 15000 1 0 0 1 1 0 1 0 0
308 10 8 308 14143 15000 1 0 0 1 1 0 1 0 0
309 10 8 309 14144 15000 1 0 0 1 1 0 1 0 0
310 10 8 310 14145 15000 1 0 0 1 1 0 1 0 0
311 10 8 311 14454 30000 1 0 0 1 1 0 1 0 0
312 10 8 312 14455 30000 1 0 0 1 1 0 1 0 0
313 10 8 313 14456 30000 1 0 0 1 1 0 1 0 0
314 10 8 314 14457 30000 1 0 0 1 1 0 1 0 0
315 10 8 315 14458 30000 1 0 0 1 1 0 1 0 0
316 10 8 316 14459 30000 1 0 0 1 1 0 1 0 0
317 10 8 317 14460 30000 1 0 0 1 1 0 1 0 0
318 10 8 318 14461 30000 1 0 0 1 1 0 1 0 0
319 10 8 319 14462 30000 1 0 0 1 1 0 1 0 0
320 10 8 320 14463 30000 1 0 0 1 1 0 1 0 0
321 10 8 321 12724 50000 1 0 0 1 1 0 1 0 0
322 10 8 322 12725 50000 1 0 0 1 1 0 1 0 0
323 10 8 323 12726 50000 1 0 0 1 1 0 1 0 0
324 10 8 324 12727 50000 1 0 0 1 1 0 1 0 0
325 10 8 325 12728 50000 1 0 0 1 1 0 1 0 0
326 10 8 326 12729 50000 1 0 0 1 1 0 1 0 0
327 10 8 327 12730 50000 1 0 0 1 1 0 1 0 0
328 10 8 328 12731 50000 1 0 0 1 1 0 1 0 0
329 10 8 329 12732 50000 1 0 0 1 1 0 1 0 0
330 10 8 330 12733 50000 1 0 0 1 1 0 1 0 0
331 10 8 331 12734 50000 1 0 0 1 1 0 1 0 0
332 10 8 332 12735 50000 1 0 0 1 1 0 1 0 0
333 10 8 333 12736 50000 1 0 0 1 1 0 1 0 0
334 10 8 334 12737 50000 1 0 0 1 1 0 1 0 0
335 10 8 335 12738 50000 1 0 0 1 1 0 1 0 0
336 10 8 336 12739 50000 1 0 0 1 1 0 1 0 0
337 10 8 337 12740 50000 1 0 0 1 1 0 1 0 0
338 10 8 338 12741 50000 1 0 0 1 1 0 1 0 0
339 10 8 339 12742 50000 1 0 0 1 1 0 1 0 0
340 10 8 340 12743 50000 1 0 0 1 1 0 1 0 0
341 10 8 341 12744 50000 1 0 0 1 1 0 1 0 0
342 10 8 342 12745 50000 1 0 0 1 1 0 1 0 0
343 10 8 343 12746 50000 1 0 0 1 1 0 1 0 0
344 10 8 344 12747 50000 1 0 0 1 1 0 1 0 0
345 10 8 345 12748 50000 1 0 0 1 1 0 1 0 0
346 10 8 346 12749 50000 1 0 0 1 1 0 1 0 0
347 10 8 347 12750 50000 1 0 0 1 1 0 1 0 0
348 10 8 348 12751 50000 1 0 0 1 1 0 1 0 0
349 10 8 349 12752 50000 1 0 0 1 1 0 1 0 0
350 10 8 350 12753 50000 1 0 0 1 1 0 1 0 0
351 10 8 351 15070 50000 1 0 0 1 1 0 1 0 0
352 10 8 352 15071 50000 1 0 0 1 1 0 1 0 0
353 10 8 353 15072 50000 1 0 0 1 1 0 1 0 0
354 10 8 354 15073 50000 1 0 0 1 1 0 1 0 0
355 10 8 355 15074 50000 1 0 0 1 1 0 1 0 0
356 10 8 356 15075 50000 1 0 0 1 1 0 1 0 0
357 10 8 357 15076 50000 1 0 0 1 1 0 1 0 0
358 10 8 358 15077 50000 1 0 0 1 1 0 1 0 0
359 10 8 359 15078 50000 1 0 0 1 1 0 1 0 0
360 10 8 360 15079 50000 1 0 0 1 1 0 1 0 0
361 10 8 361 15567 20000 1 0 0 1 1 0 1 0 0
362 10 8 362 15568 20000 1 0 0 1 1 0 1 0 0
363 10 8 363 15569 20000 1 0 0 1 1 0 1 0 0
364 10 8 364 15570 20000 1 0 0 1 1 0 1 0 0
365 10 8 365 15571 20000 1 0 0 1 1 0 1 0 0
366 10 8 366 15572 20000 1 0 0 1 1 0 1 0 0
367 10 8 367 15573 20000 1 0 0 1 1 0 1 0 0
368 10 8 368 15574 20000 1 0 0 1 1 0 1 0 0
369 10 8 369 15575 20000 1 0 0 1 1 0 1 0 0
370 10 8 370 15576 20000 1 0 0 1 1 0 1 0 0
371 10 8 371 15577 20000 1 0 0 1 1 0 1 0 0
372 10 8 372 15578 20000 1 0 0 1 1 0 1 0 0
373 10 8 373 15579 20000 1 0 0 1 1 0 1 0 0
374 10 8 374 15580 20000 1 0 0 1 1 0 1 0 0
375 10 8 375 15581 20000 1 0 0 1 1 0 1 0 0
376 10 8 376 15582 20000 1 0 0 1 1 0 1 0 0
377 10 8 377 15583 20000 1 0 0 1 1 0 1 0 0
378 10 8 378 15584 20000 1 0 0 1 1 0 1 0 0
379 10 8 379 15585 20000 1 0 0 1 1 0 1 0 0
380 10 8 380 15586 20000 1 0 0 1 1 0 1 0 0
381 10 8 381 15587 20000 1 0 0 1 1 0 1 0 0
382 10 8 382 15588 20000 1 0 0 1 1 0 1 0 0
383 10 8 383 15589 20000 1 0 0 1 1 0 1 0 0
384 10 8 384 15590 20000 1 0 0 1 1 0 1 0 0
385 10 8 385 15591 20000 1 0 0 1 1 0 1 0 0
386 10 8 386 15592 20000 1 0 0 1 1 0 1 0 0
387 10 8 387 15593 20000 1 0 0 1 1 0 1 0 0
388 10 8 388 15594 20000 1 0 0 1 1 0 1 0 0
389 10 8 389 15595 20000 1 0 0 1 1 0 1 0 0
390 10 8 390 15596 20000 1 0 0 1 1 0 1 0 0
391 10 8 391 15597 20000 1 0 0 1 1 0 1 0 0
392 10 8 392 15598 20000 1 0 0 1 1 0 1 0 0
393 10 8 393 15599 20000 1 0 0 1 1 0 1 0 0
394 10 8 394 15600 20000 1 0 0 1 1 0 1 0 0
395 10 8 395 15601 20000 1 0 0 1 1 0 1 0 0
396 10 8 396 15602 20000 1 0 0 1 1 0 1 0 0
397 10 8 397 15603 20000 1 0 0 1 1 0 1 0 0
398 10 8 398 15604 20000 1 0 0 1 1 0 1 0 0
399 10 8 399 15605 20000 1 0 0 1 1 0 1 0 0
400 10 8 400 15606 20000 1 0 0 1 1 0 1 0 0
401 10 8 401 15607 20000 1 0 0 1 1 0 1 0 0
402 10 8 402 15608 20000 1 0 0 1 1 0 1 0 0
403 10 8 403 15609 20000 1 0 0 1 1 0 1 0 0
404 10 8 404 15610 20000 1 0 0 1 1 0 1 0 0
405 10 8 405 15611 20000 1 0 0 1 1 0 1 0 0
406 10 8 406 15612 20000 1 0 0 1 1 0 1 0 0
407 10 8 407 15613 20000 1 0 0 1 1 0 1 0 0
408 10 8 408 15614 20000 1 0 0 1 1 0 1 0 0
409 10 8 409 15615 20000 1 0 0 1 1 0 1 0 0
410 10 8 410 15616 20000 1 0 0 1 1 0 1 0 0
411 10 8 411 15617 20000 1 0 0 1 1 0 1 0 0
412 10 8 412 15618 20000 1 0 0 1 1 0 1 0 0
413 10 8 413 15619 20000 1 0 0 1 1 0 1 0 0
414 10 8 414 15620 20000 1 0 0 1 1 0 1 0 0
415 10 8 415 15621 20000 1 0 0 1 1 0 1 0 0
416 10 8 416 15622 20000 1 0 0 1 1 0 1 0 0
417 10 8 417 15623 20000 1 0 0 1 1 0 1 0 0
418 10 8 418 15624 20000 1 0 0 1 1 0 1 0 0
419 10 8 419 15625 20000 1 0 0 1 1 0 1 0 0
420 10 8 420 15626 20000 1 0 0 1 1 0 1 0 0
421 10 8 421 15627 20000 1 0 0 1 1 0 1 0 0
422 10 8 422 15628 20000 1 0 0 1 1 0 1 0 0
423 10 8 423 15629 20000 1 0 0 1 1 0 1 0 0
424 10 8 424 15630 20000 1 0 0 1 1 0 1 0 0
425 10 8 425 15631 20000 1 0 0 1 1 0 1 0 0
426 10 8 426 15632 20000 1 0 0 1 1 0 1 0 0
427 10 8 427 15633 20000 1 0 0 1 1 0 1 0 0
428 10 8 428 15634 20000 1 0 0 1 1 0 1 0 0
429 10 8 429 15635 20000 1 0 0 1 1 0 1 0 0
430 10 8 430 15636 20000 1 0 0 1 1 0 1 0 0
431 10 8 431 15637 20000 1 0 0 1 1 0 1 0 0
432 10 8 432 15638 20000 1 0 0 1 1 0 1 0 0
433 10 8 433 15639 20000 1 0 0 1 1 0 1 0 0
434 10 8 434 15640 20000 1 0 0 1 1 0 1 0 0
435 10 8 435 15641 20000 1 0 0 1 1 0 1 0 0
436 10 8 436 15642 20000 1 0 0 1 1 0 1 0 0
437 10 8 437 15643 20000 1 0 0 1 1 0 1 0 0
438 10 8 438 15644 20000 1 0 0 1 1 0 1 0 0
439 10 8 439 15645 20000 1 0 0 1 1 0 1 0 0
440 10 8 440 15646 20000 1 0 0 1 1 0 1 0 0
441 10 8 441 15647 20000 1 0 0 1 1 0 1 0 0
442 10 8 442 15648 20000 1 0 0 1 1 0 1 0 0
443 10 8 443 15649 20000 1 0 0 1 1 0 1 0 0
444 10 8 444 15650 20000 1 0 0 1 1 0 1 0 0
445 10 8 445 15651 20000 1 0 0 1 1 0 1 0 0
446 10 8 446 15652 20000 1 0 0 1 1 0 1 0 0
447 10 8 447 15653 20000 1 0 0 1 1 0 1 0 0
448 10 8 448 15654 20000 1 0 0 1 1 0 1 0 0
449 10 8 449 15655 20000 1 0 0 1 1 0 1 0 0
450 10 8 450 15656 20000 1 0 0 1 1 0 1 0 0
451 10 8 451 15657 20000 1 0 0 1 1 0 1 0 0
452 10 8 452 15658 20000 1 0 0 1 1 0 1 0 0
453 10 8 453 15659 20000 1 0 0 1 1 0 1 0 0
454 10 8 454 15660 20000 1 0 0 1 1 0 1 0 0
455 10 8 455 15661 20000 1 0 0 1 1 0 1 0 0
456 10 8 456 15662 20000 1 0 0 1 1 0 1 0 0
457 10 8 457 15663 20000 1 0 0 1 1 0 1 0 0
458 10 8 458 15664 20000 1 0 0 1 1 0 1 0 0
459 10 8 459 15665 20000 1 0 0 1 1 0 1 0 0
460 10 8 460 15666 20000 1 0 0 1 1 0 1 0 0
461 10 8 461 15667 20000 1 0 0 1 1 0 1 0 0
462 10 8 462 15668 20000 1 0 0 1 1 0 1 0 0
463 10 8 463 15669 20000 1 0 0 1 1 0 1 0 0
464 10 8 464 15670 20000 1 0 0 1 1 0 1 0 0
465 10 8 465 15671 20000 1 0 0 1 1 0 1 0 0
466 10 8 466 15672 20000 1 0 0 1 1 0 1 0 0
467 10 8 467 15673 20000 1 0 0 1 1 0 1 0 0
468 10 8 468 15674 20000 1 0 0 1 1 0 1 0 0
469 10 8 469 15675 20000 1 0 0 1 1 0 1 0 0
470 10 8 470 15676 20000 1 0 0 1 1 0 1 0 0
471 10 8 471 15677 20000 1 0 0 1 1 0 1 0 0
472 10 8 472 15678 20000 1 0 0 1 1 0 1 0 0
473 10 8 473 15679 20000 1 0 0 1 1 0 1 0 0
474 10 8 474 15680 20000 1 0 0 1 1 0 1 0 0
475 10 8 475 15681 20000 1 0 0 1 1 0 1 0 0
476 10 8 476 15682 20000 1 0 0 1 1 0 1 0 0
477 10 8 477 15683 20000 1 0 0 1 1 0 1 0 0
478 10 8 478 15684 20000 1 0 0 1 1 0 1 0 0
479 10 8 479 15685 20000 1 0 0 1 1 0 1 0 0
480 10 8 480 15686 20000 1 0 0 1 1 0 1 0 0
481 10 8 481 15687 20000 1 0 0 1 1 0 1 0 0
482 10 8 482 15688 20000 1 0 0 1 1 0 1 0 0
483 10 8 483 15689 20000 1 0 0 1 1 0 1 0 0
484 10 8 484 15690 20000 1 0 0 1 1 0 1 0 0
485 10 8 485 15691 20000 1 0 0 1 1 0 1 0 0
486 10 8 486 15692 20000 1 0 0 1 1 0 1 0 0
487 10 8 487 15693 20000 1 0 0 1 1 0 1 0 0
488 10 8 488 15694 20000 1 0 0 1 1 0 1 0 0
489 10 8 489 15695 20000 1 0 0 1 1 0 1 0 0
490 10 8 490 15696 20000 1 0 0 1 1 0 1 0 0
491 10 8 491 15697 20000 1 0 0 1 1 0 1 0 0
492 10 8 492 15698 20000 1 0 0 1 1 0 1 0 0
493 10 8 493 15699 20000 1 0 0 1 1 0 1 0 0
494 10 8 494 15700 20000 1 0 0 1 1 0 1 0 0
495 10 8 495 15701 20000 1 0 0 1 1 0 1 0 0
496 10 8 496 15702 20000 1 0 0 1 1 0 1 0 0
497 10 8 497 15703 20000 1 0 0 1 1 0 1 0 0
498 10 8 498 15704 20000 1 0 0 1 1 0 1 0 0
499 10 8 499 15705 20000 1 0 0 1 1 0 1 0 0
500 10 8 500 15706 20000 1 0 0 1 1 0 1 0 0
501 10 8 501 15707 20000 1 0 0 1 1 0 1 0 0
502 10 8 502 15708 20000 1 0 0 1 1 0 1 0 0
503 10 8 503 15709 20000 1 0 0 1 1 0 1 0 0
504 10 8 504 15710 20000 1 0 0 1 1 0 1 0 0
505 10 8 505 15711 20000 1 0 0 1 1 0 1 0 0
506 10 8 506 15712 20000 1 0 0 1 1 0 1 0 0
507 10 8 507 15713 20000 1 0 0 1 1 0 1 0 0
508 10 8 508 15714 20000 1 0 0 1 1 0 1 0 0
509 10 8 509 15715 20000 1 0 0 1 1 0 1 0 0
510 10 8 510 15716 20000 1 0 0 1 1 0 1 0 0
511 10 8 511 15717 20000 1 0 0 1 1 0 1 0 0
512 10 8 512 15718 20000 1 0 0 1 1 0 1 0 0
513 10 8 513 15719 20000 1 0 0 1 1 0 1 0 0
514 10 8 514 15720 20000 1 0 0 1 1 0 1 0 0
515 10 8 515 15721 20000 1 0 0 1 1 0 1 0 0
516 10 8 516 15722 20000 1 0 0 1 1 0 1 0 0
517 10 8 517 15723 20000 1 0 0 1 1 0 1 0 0
518 10 8 518 15724 20000 1 0 0 1 1 0 1 0 0
519 10 8 519 15725 20000 1 0 0 1 1 0 1 0 0
520 10 8 520 15726 20000 1 0 0 1 1 0 1 0 0
521 10 8 521 15727 20000 1 0 0 1 1 0 1 0 0
522 10 8 522 15728 20000 1 0 0 1 1 0 1 0 0
523 10 8 523 15729 20000 1 0 0 1 1 0 1 0 0
524 10 8 524 15730 20000 1 0 0 1 1 0 1 0 0
525 10 8 525 15731 20000 1 0 0 1 1 0 1 0 0
526 10 8 526 15732 20000 1 0 0 1 1 0 1 0 0
527 10 8 527 15733 20000 1 0 0 1 1 0 1 0 0
528 10 8 528 15734 20000 1 0 0 1 1 0 1 0 0
529 10 8 529 15735 20000 1 0 0 1 1 0 1 0 0
530 10 8 530 15736 20000 1 0 0 1 1 0 1 0 0
531 10 8 531 15737 20000 1 0 0 1 1 0 1 0 0
532 10 8 532 15738 20000 1 0 0 1 1 0 1 0 0
533 10 8 533 15739 20000 1 0 0 1 1 0 1 0 0
534 10 8 534 15740 20000 1 0 0 1 1 0 1 0 0
535 10 8 535 15741 20000 1 0 0 1 1 0 1 0 0
536 10 8 536 15742 20000 1 0 0 1 1 0 1 0 0
537 10 8 537 15743 20000 1 0 0 1 1 0 1 0 0
538 10 8 538 15744 20000 1 0 0 1 1 0 1 0 0
539 10 8 539 15745 20000 1 0 0 1 1 0 1 0 0
540 10 8 540 15746 20000 1 0 0 1 1 0 1 0 0
541 10 8 541 15747 20000 1 0 0 1 1 0 1 0 0
542 10 8 542 15748 20000 1 0 0 1 1 0 1 0 0
543 10 8 543 15749 20000 1 0 0 1 1 0 1 0 0
544 10 8 544 15750 20000 1 0 0 1 1 0 1 0 0
545 10 8 545 15751 20000 1 0 0 1 1 0 1 0 0
546 10 8 546 15752 20000 1 0 0 1 1 0 1 0 0
547 10 8 547 15753 20000 1 0 0 1 1 0 1 0 0
548 10 8 548 15754 20000 1 0 0 1 1 0 1 0 0
549 10 8 549 15755 20000 1 0 0 1 1 0 1 0 0
550 10 8 550 15756 20000 1 0 0 1 1 0 1 0 0
551 10 8 551 15757 20000 1 0 0 1 1 0 1 0 0
552 10 8 552 15758 20000 1 0 0 1 1 0 1 0 0
553 10 8 553 15759 20000 1 0 0 1 1 0 1 0 0
554 10 8 554 15760 20000 1 0 0 1 1 0 1 0 0
555 10 8 555 15761 20000 1 0 0 1 1 0 1 0 0
556 10 8 556 15762 20000 1 0 0 1 1 0 1 0 0
557 10 8 557 15763 20000 1 0 0 1 1 0 1 0 0
558 10 8 558 15764 20000 1 0 0 1 1 0 1 0 0
559 10 8 559 15765 20000 1 0 0 1 1 0 1 0 0
560 10 8 560 15766 20000 1 0 0 1 1 0 1 0 0
561 10 8 561 15919 20000 1 0 0 1 1 0 1 0 0
562 10 8 562 15920 20000 1 0 0 1 1 0 1 0 0
563 10 8 563 15921 20000 1 0 0 1 1 0 1 0 0
564 10 8 564 15922 20000 1 0 0 1 1 0 1 0 0
565 10 8 565 15923 20000 1 0 0 1 1 0 1 0 0
566 10 8 566 15924 20000 1 0 0 1 1 0 1 0 0
567 10 8 567 15925 20000 1 0 0 1 1 0 1 0 0
568 10 8 568 15926 20000 1 0 0 1 1 0 1 0 0
569 10 8 569 15927 20000 1 0 0 1 1 0 1 0 0
570 10 8 570 15928 20000 1 0 0 1 1 0 1 0 0
571 10 8 571 15929 20000 1 0 0 1 1 0 1 0 0
572 10 8 572 15930 20000 1 0 0 1 1 0 1 0 0
573 10 8 573 15931 20000 1 0 0 1 1 0 1 0 0
574 10 8 574 15932 20000 1 0 0 1 1 0 1 0 0
575 10 8 575 15933 20000 1 0 0 1 1 0 1 0 0
576 10 8 576 15934 20000 1 0 0 1 1 0 1 0 0
577 10 8 577 15935 20000 1 0 0 1 1 0 1 0 0
578 10 8 578 15936 20000 1 0 0 1 1 0 1 0 0
579 10 8 579 15937 20000 1 0 0 1 1 0 1 0 0
580 10 8 580 15938 20000 1 0 0 1 1 0 1 0 0
581 10 8 581 15939 20000 1 0 0 1 1 0 1 0 0
582 10 8 582 15940 20000 1 0 0 1 1 0 1 0 0
583 10 8 583 15941 20000 1 0 0 1 1 0 1 0 0
584 10 8 584 15942 20000 1 0 0 1 1 0 1 0 0
585 10 8 585 15943 20000 1 0 0 1 1 0 1 0 0
586 10 8 586 15944 20000 1 0 0 1 1 0 1 0 0
587 10 8 587 15945 20000 1 0 0 1 1 0 1 0 0
588 10 8 588 15946 20000 1 0 0 1 1 0 1 0 0
589 10 8 589 15947 20000 1 0 0 1 1 0 1 0 0
590 10 8 590 15948 20000 1 0 0 1 1 0 1 0 0
591 10 8 591 15949 20000 1 0 0 1 1 0 1 0 0
592 10 8 592 15950 20000 1 0 0 1 1 0 1 0 0
593 10 8 593 15951 20000 1 0 0 1 1 0 1 0 0
594 10 8 594 15952 20000 1 0 0 1 1 0 1 0 0
595 10 8 595 15953 20000 1 0 0 1 1 0 1 0 0
596 10 8 596 15954 20000 1 0 0 1 1 0 1 0 0
597 10 8 597 15955 20000 1 0 0 1 1 0 1 0 0
598 10 8 598 15956 20000 1 0 0 1 1 0 1 0 0
599 10 8 599 15957 20000 1 0 0 1 1 0 1 0 0
600 10 8 600 15958 20000 1 0 0 1 1 0 1 0 0
601 10 8 601 15959 20000 1 0 0 1 1 0 1 0 0
602 10 8 602 15960 20000 1 0 0 1 1 0 1 0 0
603 10 8 603 15961 20000 1 0 0 1 1 0 1 0 0
604 10 8 604 15962 20000 1 0 0 1 1 0 1 0 0
605 10 8 605 15963 20000 1 0 0 1 1 0 1 0 0
606 10 8 606 15964 20000 1 0 0 1 1 0 1 0 0
607 10 8 607 15965 20000 1 0 0 1 1 0 1 0 0
608 10 8 608 15966 20000 1 0 0 1 1 0 1 0 0
609 10 8 609 15967 20000 1 0 0 1 1 0 1 0 0
610 10 8 610 15968 20000 1 0 0 1 1 0 1 0 0
611 10 7 611 13506 250 1 0 0 1 1 0 1 50 0
612 10 7 612 15011 250 1 0 0 1 1 0 1 50 0
613 10 7 613 13636 250 1 0 0 1 1 0 1 50 0
614 10 7 614 1227 250 1 0 0 1 1 0 1 50 0
615 10 7 615 15022 250 1 0 0 1 1 0 1 50 0
616 10 8 616 4407 1000 1 0 0 1 1 0 1 0 0
617 10 8 617 4408 1000 1 0 0 1 1 0 1 0 0
618 10 8 618 4409 1000 1 0 0 1 1 0 1 0 0
619 10 8 619 4410 1000 1 0 0 1 1 0 1 0 0
620 10 8 620 4411 1000 1 0 0 1 1 0 1 0 0
621 10 8 621 4412 1000 1 0 0 1 1 0 1 0 0
622 10 8 622 4413 1000 1 0 0 1 1 0 1 0 0
623 10 8 623 4414 1000 1 0 0 1 1 0 1 0 0
624 10 8 624 4823 1000 1 0 0 1 1 0 1 0 0
625 10 8 625 4824 1000 1 0 0 1 1 0 1 0 0
626 10 8 626 4825 1000 1 0 0 1 1 0 1 0 0
627 10 8 627 4826 1000 1 0 0 1 1 0 1 0 0
628 10 8 628 4827 1000 1 0 0 1 1 0 1 0 0
629 10 8 629 4828 1000 1 0 0 1 1 0 1 0 0
630 10 8 630 4829 1000 1 0 0 1 1 0 1 0 0
631 10 8 631 4830 1000 1 0 0 1 1 0 1 0 0
632 10 8 632 5194 1000 1 0 0 1 1 0 1 0 0
633 10 8 633 5195 1000 1 0 0 1 1 0 1 0 0
634 10 8 634 5196 1000 1 0 0 1 1 0 1 0 0
635 10 8 635 5197 1000 1 0 0 1 1 0 1 0 0
636 10 8 636 5198 1000 1 0 0 1 1 0 1 0 0
637 10 8 637 5199 1000 1 0 0 1 1 0 1 0 0
638 10 8 638 5200 1000 1 0 0 1 1 0 1 0 0
639 10 8 639 5201 1000 1 0 0 1 1 0 1 0 0
640 10 8 640 13630 1000 1 0 0 1 1 0 1 0 0
641 10 8 641 13631 1000 1 0 0 1 1 0 1 0 0
642 10 8 642 13632 1000 1 0 0 1 1 0 1 0 0
643 10 8 643 13633 1000 1 0 0 1 1 0 1 0 0
644 10 8 644 13634 1000 1 0 0 1 1 0 1 0 0
645 10 8 645 13635 1000 1 0 0 1 1 0 1 0 0
646 10 8 646 15103 1000 1 0 0 1 1 0 1 0 0
647 10 8 647 15104 1000 1 0 0 1 1 0 1 0 0
648 10 8 648 15105 1000 1 0 0 1 1 0 1 0 0
649 10 8 649 15106 1000 1 0 0 1 1 0 1 0 0
650 10 8 650 15107 1000 1 0 0 1 1 0 1 0 0
651 10 8 651 15108 1000 1 0 0 1 1 0 1 0 0
652 10 8 652 16459 1000 1 0 0 1 1 0 1 0 0
653 10 8 653 16460 1000 1 0 0 1 1 0 1 0 0
654 10 8 654 16461 1000 1 0 0 1 1 0 1 0 0
655 10 8 655 16462 1000 1 0 0 1 1 0 1 0 0
656 10 8 656 16463 1000 1 0 0 1 1 0 1 0 0
657 10 8 657 16464 1000 1 0 0 1 1 0 1 0 0
658 10 8 658 16465 1000 1 0 0 1 1 0 1 0 0
659 10 8 659 16466 1000 1 0 0 1 1 0 1 0 0
660 10 8 660 16467 1000 1 0 0 1 1 0 1 0 0
661 10 8 661 16468 1000 1 0 0 1 1 0 1 0 0
662 10 8 662 16469 1000 1 0 0 1 1 0 1 0 0
663 10 8 663 16470 1000 1 0 0 1 1 0 1 0 0
664 10 8 664 16471 1000 1 0 0 1 1 0 1 0 0
665 10 8 665 16472 1000 1 0 0 1 1 0 1 0 0
666 10 8 666 13416 1000 1 0 0 1 1 0 1 0 0
667 10 8 667 13417 1000 1 0 0 1 1 0 1 0 0
668 10 8 668 13418 1000 1 0 0 1 1 0 1 0 0
669 10 8 669 13419 1000 1 0 0 1 1 0 1 0 0
670 10 8 670 13420 1000 1 0 0 1 1 0 1 0 0
671 10 8 671 14283 1000 1 0 0 1 1 0 1 0 0
672 10 8 672 14284 1000 1 0 0 1 1 0 1 0 0
673 10 8 673 14285 1000 1 0 0 1 1 0 1 0 0
674 10 8 674 14286 1000 1 0 0 1 1 0 1 0 0
675 10 8 675 13182 1000 1 0 0 1 1 0 1 0 0
676 10 8 676 13507 1000 1 0 0 1 1 0 1 0 0
677 10 8 677 13981 1000 1 0 0 1 1 0 1 0 0
678 10 8 678 14744 1000 1 0 0 1 1 0 1 0 0
679 10 8 679 14893 1000 1 0 0 1 1 0 1 0 0
680 10 8 680 15785 1000 1 0 0 1 1 0 1 0 0
681 10 8 681 16419 1000 1 0 0 1 1 0 1 0 0
682 10 8 682 11470 1000 1 0 0 1 1 0 1 0 0
683 10 8 683 12512 1000 1 0 0 1 1 0 1 0 0
684 10 8 684 12884 1000 1 0 0 1 1 0 1 0 0
685 10 8 685 12513 1000 1 0 0 1 1 0 1 0 0
686 10 8 686 12514 1000 1 0 0 1 1 0 1 0 0
687 10 8 687 12515 1000 1 0 0 1 1 0 1 0 0
688 10 8 688 12516 1000 1 0 0 1 1 0 1 0 0
689 10 8 689 12517 1000 1 0 0 1 1 0 1 0 0
690 10 8 690 12518 1000 1 0 0 1 1 0 1 0 0
691 10 8 691 12519 1000 1 0 0 1 1 0 1 0 0
692 10 8 692 12520 1000 1 0 0 1 1 0 1 0 0
693 10 8 693 12521 1000 1 0 0 1 1 0 1 0 0
694 10 8 694 8179 1000 1 0 0 1 1 0 1 0 0
695 10 8 695 9704 1000 1 0 0 1 1 0 1 0 0
696 10 8 696 15448 1000 1 0 0 1 1 0 1 0 0
697 10 8 697 11162 1000 1 0 0 1 1 0 1 0 0
698 10 8 698 11163 1000 1 0 0 1 1 0 1 0 0
699 10 8 699 11164 1000 1 0 0 1 1 0 1 0 0
700 10 8 700 11165 1000 1 0 0 1 1 0 1 0 0
701 10 8 701 11661 1000 1 0 0 1 1 0 1 0 0
702 10 8 702 11662 1000 1 0 0 1 1 0 1 0 0
703 10 8 703 14639 1000 1 0 0 1 1 0 1 0 0
704 10 8 704 13607 10 1 0 0 1 1 0 1 0 0
705 10 7 705 15774 3000 1 0 0 1 1 0 1 100 0
706 10 7 706 15775 3000 1 0 0 1 1 0 1 100 0
707 10 7 707 11420 3000 1 0 0 1 1 0 1 100 0
708 10 7 708 14704 3000 1 0 0 1 1 0 1 100 0
709 10 7 709 13177 3000 1 0 0 1 1 0 1 100 0
710 10 7 710 14191 3000 1 0 0 1 1 0 1 100 0
711 10 7 711 13449 3000 1 0 0 1 1 0 1 100 0
712 10 7 712 14192 3000 1 0 0 1 1 0 1 100 0
713 10 7 713 15772 3000 1 0 0 1 1 0 1 100 0
714 10 7 714 13791 3000 1 0 0 1 1 0 1 100 0
715 10 7 715 14006 3000 1 0 0 1 1 0 1 100 0
716 10 7 716 15768 3000 1 0 0 1 1 0 1 100 0
717 10 7 717 14069 3000 1 0 0 1 1 0 1 100 0
718 10 7 718 14124 3000 1 0 0 1 1 0 1 100 0
719 10 7 719 15507 3000 1 0 0 1 1 0 1 100 0
720 10 7 720 15508 3000 1 0 0 1 1 0 1 100 0
721 10 7 721 14855 3000 1 0 0 1 1 0 1 100 0
722 10 7 722 14894 3000 1 0 0 1 1 0 1 100 0
723 10 7 723 16444 3000 1 0 0 1 1 0 1 100 0
724 10 7 724 16445 3000 1 0 0 1 1 0 1 100 0
725 10 7 725 12509 3000 1 0 0 1 1 0 1 100 0
726 10 7 726 14126 3000 1 0 0 1 1 0 1 100 0
727 10 7 727 15062 3000 1 0 0 1 1 0 1 100 0
728 10 7 728 15063 3000 1 0 0 1 1 0 1 100 0
729 10 7 729 14891 3000 1 0 0 1 1 0 1 100 0
730 10 7 730 14895 3000 1 0 0 1 1 0 1 100 0
731 10 7 731 14091 3000 1 0 0 1 1 0 1 100 0
732 10 7 732 14092 3000 1 0 0 1 1 0 1 100 0
733 10 7 733 14501 3000 1 0 0 1 1 0 1 100 0
734 10 7 734 14506 3000 1 0 0 1 1 0 1 100 0
735 10 7 735 15285 3000 1 0 0 1 1 0 1 100 0
736 10 7 736 15286 3000 1 0 0 1 1 0 1 100 0
737 10 7 737 16442 3000 1 0 0 1 1 0 1 100 0
738 10 7 738 16443 3000 1 0 0 1 1 0 1 100 0
739 10 7 739 15027 3000 1 0 0 1 1 0 1 100 0
740 10 7 740 15028 3000 1 0 0 1 1 0 1 100 0
741 10 7 741 13453 3000 1 0 0 1 1 0 1 100 0
742 10 7 742 14193 3000 1 0 0 1 1 0 1 100 0
743 10 7 743 13178 3000 1 0 0 1 1 0 1 100 0
744 10 7 744 14194 3000 1 0 0 1 1 0 1 100 0
745 10 7 745 16454 3000 1 0 0 1 1 0 1 100 0
746 10 7 746 16455 3000 1 0 0 1 1 0 1 100 0
747 10 7 747 15030 3000 1 0 0 1 1 0 1 100 0
748 10 7 748 15031 3000 1 0 0 1 1 0 1 100 0
749 10 7 749 13790 3000 1 0 0 1 1 0 1 100 0
750 10 7 750 14005 3000 1 0 0 1 1 0 1 100 0
751 10 7 751 14406 3000 1 0 0 1 1 0 1 100 0
752 10 7 752 14413 3000 1 0 0 1 1 0 1 100 0
753 10 7 753 16448 3000 1 0 0 1 1 0 1 100 0
754 10 7 754 16449 3000 1 0 0 1 1 0 1 100 0
755 10 7 755 12872 3000 1 0 0 1 1 0 1 100 0
756 10 7 756 14187 3000 1 0 0 1 1 0 1 100 0
757 10 7 757 14125 3000 1 0 0 1 1 0 1 100 0
758 10 7 758 14500 3000 1 0 0 1 1 0 1 100 0
759 10 7 759 14505 3000 1 0 0 1 1 0 1 100 0
760 10 7 760 15118 3000 1 0 0 1 1 0 1 100 0
761 10 7 761 15119 3000 1 0 0 1 1 0 1 100 0
762 10 7 762 14662 3000 1 0 0 1 1 0 1 100 0
763 10 7 763 14663 3000 1 0 0 1 1 0 1 100 0
764 10 7 764 15771 3000 1 0 0 1 1 0 1 100 0
765 10 7 765 9700 3000 1 0 0 1 1 0 1 100 0
766 10 7 766 14498 3000 1 0 0 1 1 0 1 100 0
767 10 7 767 14913 3000 1 0 0 1 1 0 1 100 0
768 10 7 768 14914 3000 1 0 0 1 1 0 1 100 0
769 10 7 769 13508 3000 1 0 0 1 1 0 1 100 0
770 10 7 770 15115 3000 1 0 0 1 1 0 1 100 0
771 10 7 771 15116 3000 1 0 0 1 1 0 1 100 0
772 10 7 772 15113 3000 1 0 0 1 1 0 1 100 0
773 10 7 773 15114 3000 1 0 0 1 1 0 1 100 0
774 10 7 774 15222 3000 1 0 0 1 1 0 1 100 0
775 10 7 775 15223 3000 1 0 0 1 1 0 1 100 0
776 10 7 776 10750 3000 1 0 0 1 1 0 1 100 0
777 10 7 777 14705 3000 1 0 0 1 1 0 1 100 0
778 10 7 778 15027 3000 1 0 0 1 1 0 1 100 0
779 10 7 779 15028 3000 1 0 0 1 1 0 1 100 0
780 10 7 780 10380 3000 1 0 0 1 1 0 1 100 0
781 10 7 781 15060 3000 1 0 0 1 1 0 1 100 0
782 10 7 782 13963 3000 1 0 0 1 1 0 1 100 0
783 10 7 783 14026 3000 1 0 0 1 1 0 1 100 0
784 10 7 784 13964 3000 1 0 0 1 1 0 1 100 0
785 10 7 785 14027 3000 1 0 0 1 1 0 1 100 0
786 10 7 786 15064 3000 1 0 0 1 1 0 1 100 0
787 10 7 787 15065 3000 1 0 0 1 1 0 1 100 0
788 10 7 788 15524 3000 1 0 0 1 1 0 1 100 0
789 10 7 789 15525 3000 1 0 0 1 1 0 1 100 0
790 10 7 790 16450 3000 1 0 0 1 1 0 1 100 0
791 10 7 791 16451 3000 1 0 0 1 1 0 1 100 0
792 10 7 792 16344 3000 1 0 0 1 1 0 1 100 0
793 10 7 793 16345 3000 1 0 0 1 1 0 1 100 0
794 10 7 794 16342 3000 1 0 0 1 1 0 1 100 0
795 10 7 795 16343 3000 1 0 0 1 1 0 1 100 0
796 10 7 796 15220 3000 1 0 0 1 1 0 1 100 0
797 10 7 797 15221 3000 1 0 0 1 1 0 1 100 0
798 10 7 798 15066 3000 1 0 0 1 1 0 1 100 0
799 10 7 799 15067 3000 1 0 0 1 1 0 1 100 0
800 10 7 800 14089 3000 1 0 0 1 1 0 1 100 0
801 10 7 801 14090 3000 1 0 0 1 1 0 1 100 0
802 10 7 802 14195 3000 1 0 0 1 1 0 1 100 0
803 10 7 803 14196 3000 1 0 0 1 1 0 1 100 0
804 10 7 804 13965 3000 1 0 0 1 1 0 1 100 0
805 10 7 805 14028 3000 1 0 0 1 1 0 1 100 0
806 10 7 806 13508 3000 1 0 0 1 1 0 1 100 0
807 10 7 807 13962 3000 1 0 0 1 1 0 1 100 0
808 10 7 808 14314 3000 1 0 0 1 1 0 1 100 0
809 10 7 809 13404 3000 1 0 0 1 1 0 1 100 0
810 10 7 810 14188 3000 1 0 0 1 1 0 1 100 0
811 10 7 811 14032 3000 1 0 0 1 1 0 1 100 0
812 10 7 812 13960 3000 1 0 0 1 1 0 1 100 0
813 10 7 813 15819 3000 1 0 0 1 1 0 1 100 0
814 10 7 814 15820 3000 1 0 0 1 1 0 1 100 0
815 10 7 815 10750 3000 1 0 0 1 1 0 1 100 0
816 10 7 816 14705 3000 1 0 0 1 1 0 1 100 0
817 10 7 817 14407 3000 1 0 0 1 1 0 1 100 0
818 10 7 818 14414 3000 1 0 0 1 1 0 1 100 0
819 10 7 819 16352 3000 1 0 0 1 1 0 1 100 0
820 10 7 820 16353 3000 1 0 0 1 1 0 1 100 0
821 10 7 821 14502 3000 1 0 0 1 1 0 1 100 0
822 10 7 822 14507 3000 1 0 0 1 1 0 1 100 0
823 10 7 823 10811 3000 1 0 0 1 1 0 1 100 0
824 10 7 824 15061 3000 1 0 0 1 1 0 1 100 0
825 10 7 825 15823 3000 1 0 0 1 1 0 1 100 0
826 10 7 826 15824 3000 1 0 0 1 1 0 1 100 0
827 10 7 827 15224 3000 1 0 0 1 1 0 1 100 0
828 10 7 828 15225 3000 1 0 0 1 1 0 1 100 0
829 10 7 829 14503 3000 1 0 0 1 1 0 1 100 0
830 10 7 830 14510 3000 1 0 0 1 1 0 1 100 0
831 10 7 831 15776 3000 1 0 0 1 1 0 1 100 0
832 10 7 832 15777 3000 1 0 0 1 1 0 1 100 0
833 10 7 833 15821 3000 1 0 0 1 1 0 1 100 0
834 10 7 834 15822 3000 1 0 0 1 1 0 1 100 0
835 10 7 835 14198 3000 1 0 0 1 1 0 1 100 0
836 10 7 836 14197 3000 1 0 0 1 1 0 1 100 0
837 10 7 837 16446 3000 1 0 0 1 1 0 1 100 0
838 10 7 838 16447 3000 1 0 0 1 1 0 1 100 0
839 10 7 839 14905 3000 1 0 0 1 1 0 1 100 0
840 10 7 840 14907 3000 1 0 0 1 1 0 1 100 0
841 10 7 841 14904 3000 1 0 0 1 1 0 1 100 0
842 10 7 842 14906 3000 1 0 0 1 1 0 1 100 0
843 10 7 843 14659 3000 1 0 0 1 1 0 1 100 0
844 10 7 844 14660 3000 1 0 0 1 1 0 1 100 0
845 10 7 845 13326 3000 1 0 0 1 1 0 1 100 0
846 10 7 846 14416 3000 1 0 0 1 1 0 1 100 0
847 10 7 847 13450 3000 1 0 0 1 1 0 1 100 0
848 10 7 848 14031 3000 1 0 0 1 1 0 1 100 0
849 10 7 849 16492 3000 1 0 0 1 1 0 1 100 0
850 10 7 850 16493 3000 1 0 0 1 1 0 1 100 0
851 10 8 851 1520 1 1 0 0 1 1 0 1 0 0
852 10 8 852 7011 1 1 0 0 1 1 0 1 0 0
853 10 7 853 14299 500 1 0 0 1 1 0 1 20 0
854 10 7 854 14389 500 1 0 0 1 1 0 1 20 0
855 10 7 855 15177 500 1 0 0 1 1 0 1 20 0
856 10 7 856 14537 500 1 0 0 1 1 0 1 20 0
857 10 7 857 14758 500 1 0 0 1 1 0 1 20 0
858 10 7 858 14854 500 1 0 0 1 1 0 1 20 0
859 10 7 859 13974 500 1 0 0 1 1 0 1 20 0
860 10 7 860 15021 500 1 0 0 1 1 0 1 20 0
861 10 7 861 15111 500 1 0 0 1 1 0 1 20 0
862 10 7 862 15226 500 1 0 0 1 1 0 1 20 0
863 10 7 863 15773 500 1 0 0 1 1 0 1 20 0
864 10 7 864 15825 500 1 0 0 1 1 0 1 20 0
865 10 7 865 15827 500 1 0 0 1 1 0 1 20 0
866 10 7 866 16340 500 1 0 0 1 1 0 1 20 0
867 10 7 867 16341 500 1 0 0 1 1 0 1 20 0
868 10 7 868 16457 500 1 0 0 1 1 0 1 20 0
869 10 7 869 16458 500 1 0 0 1 1 0 1 20 0
870 10 7 870 11698 250 1 0 0 1 1 0 1 50 0
871 10 7 871 11700 250 1 0 0 1 1 0 1 50 0
872 10 8 872 4358 10 1 0 0 1 1 0 1 0 0
873 10 8 873 7981 1 1 0 0 1 1 0 1 0 0
874 10 8 874 7267 20 1 0 0 1 1 0 1 0 0
875 10 8 875 9958 20 1 0 0 1 1 0 1 0 999
876 10 8 876 1548 20 1 0 0 1 1 0 1 0 0
877 10 8 877 1613 20 1 0 0 1 1 0 1 0 0
878 10 8 878 1026 1 1 0 0 1 1 0 1 0 0
879 10 8 879 5380 1 1 0 0 1 1 0 1 0 0
880 10 8 880 11284 15 1 0 0 1 1 0 1 0 0
881 10 8 881 11285 15 1 0 0 1 1 0 1 0 0
882 10 8 882 11286 15 1 0 0 1 1 0 1 0 0
883 10 8 883 10356 500 1 0 0 1 1 0 1 0 0
884 10 8 884 12511 500 1 0 0 1 1 0 1 0 0
885 10 8 885 13238 500 1 0 0 1 1 0 1 0 0
886 10 8 886 1691 1 1 0 0 1 1 0 1 0 0
887 10 8 887 9708 1 1 0 0 1 1 0 1 0 0
888 10 8 888 11383 10 1 0 0 1 1 0 1 0 0
889 10 8 889 11382 10 1 0 0 1 1 0 1 0 0
890 10 8 890 11381 10 1 0 0 1 1 0 1 0 0
891 10 7 891 16348 3000 1 0 0 1 1 0 1 100 0
892 10 8 892 11386 10 1 0 0 1 1 0 1 0 0
893 10 8 893 5767 1 10000 0 0 1 1 0 1 0 0
894 10 8 894 5765 1 10000 0 0 1 1 0 1 0 0
895 10 8 895 5768 1 10000 0 0 1 1 0 1 0 0
896 10 8 896 14444 10 1 0 0 1 1 0 1 0 0
897 10 8 897 14443 10 1 0 0 1 1 0 1 0 0
898 10 8 898 14445 10 1 0 0 1 1 0 1 0 0
899 10 8 899 15068 500 1 0 0 1 1 0 1 20 0
900 10 7 900 16532 1000 1 0 0 1 1 0 1 0 0
901 10 8 901 100 1 10000 0 0 1 1 0 1 0 0
902 10 8 902 11243 1 1 0 0 1 1 0 1 0 0
903 10 8 903 101 1 10000 0 0 1 1 0 1 0 0
904 10 7 904 14368 3000 1 0 0 1 1 0 1 50 0
905 10 8 905 8943 1 20 0 0 1 1 0 1 0 0
906 10 7 906 1622 3000 1 0 0 1 1 0 1 0 0
907 10 8 907 8953 1 20 0 0 1 1 0 1 0 0
908 10 8 908 13693 1 20 0 0 1 1 0 1 0 0
909 10 8 909 8949 1 20 0 0 1 1 0 1 0 0
910 10 8 910 8955 1 20 0 0 1 1 0 1 0 0
911 10 7 911 16456 500 1 0 0 1 1 0 1 0 0

0
bin/questlists/.gitkeep Normal file
View File

View File

@@ -0,0 +1,260 @@
BEGIN;
-- Ripped prizes
INSERT INTO public.festa_prizes
(type, tier, souls_req, item_id, num_item)
VALUES
('personal', 1, 1, 9647, 7),
('personal', 2, 1, 9647, 7),
('personal', 3, 1, 9647, 7),
('personal', 1, 200, 11284, 4),
('personal', 2, 200, 11284, 4),
('personal', 3, 200, 11284, 4),
('personal', 1, 400, 11381, 3),
('personal', 2, 400, 11381, 3),
('personal', 3, 400, 11381, 3),
('personal', 1, 600, 11284, 8),
('personal', 2, 600, 11284, 8),
('personal', 3, 600, 11284, 8),
('personal', 1, 800, 11384, 3),
('personal', 2, 800, 11384, 3),
('personal', 3, 800, 11384, 3),
('personal', 1, 1000, 11284, 12),
('personal', 2, 1000, 11284, 12),
('personal', 3, 1000, 11284, 12),
('personal', 1, 1200, 11381, 5),
('personal', 2, 1200, 11381, 5),
('personal', 3, 1200, 11381, 5),
('personal', 1, 1400, 11284, 16),
('personal', 2, 1400, 11284, 16),
('personal', 3, 1400, 11284, 16),
('personal', 1, 1700, 11384, 5),
('personal', 2, 1700, 11384, 5),
('personal', 3, 1700, 11384, 5),
('personal', 1, 2000, 11284, 16),
('personal', 2, 2000, 11284, 16),
('personal', 3, 2000, 11284, 16),
('personal', 1, 2500, 11382, 4),
('personal', 2, 2500, 11382, 4),
('personal', 3, 2500, 11382, 4),
('personal', 1, 3000, 11284, 24),
('personal', 2, 3000, 11284, 24),
('personal', 3, 3000, 11284, 24),
('personal', 1, 4000, 11385, 4),
('personal', 2, 4000, 11385, 4),
('personal', 3, 4000, 11385, 4),
('personal', 1, 5000, 11381, 11),
('personal', 2, 5000, 11381, 11),
('personal', 3, 5000, 11381, 11),
('personal', 1, 6000, 5177, 5),
('personal', 2, 6000, 5177, 5),
('personal', 3, 6000, 5177, 5),
('personal', 1, 7000, 11384, 11),
('personal', 2, 7000, 11384, 11),
('personal', 3, 7000, 11384, 11),
('personal', 1, 10000, 11382, 8),
('personal', 2, 10000, 11382, 8),
('personal', 3, 10000, 11382, 8),
('personal', 1, 15000, 11385, 4),
('personal', 2, 15000, 11385, 4),
('personal', 3, 15000, 11385, 4),
('personal', 1, 20000, 11381, 13),
('personal', 2, 20000, 11381, 13),
('personal', 3, 20000, 11381, 13),
('personal', 1, 25000, 11385, 4),
('personal', 2, 25000, 11385, 4),
('personal', 3, 25000, 11385, 4),
('personal', 1, 30000, 11383, 1),
('personal', 2, 30000, 11383, 1),
('personal', 3, 30000, 11383, 1);
INSERT INTO public.festa_prizes
(type, tier, souls_req, item_id, num_item)
VALUES
('guild', 1, 100, 7468, 5),
('guild', 2, 100, 7468, 5),
('guild', 3, 100, 7465, 5),
('guild', 1, 300, 7469, 5),
('guild', 2, 300, 7469, 5),
('guild', 3, 300, 7466, 5),
('guild', 1, 700, 7470, 5),
('guild', 2, 700, 7470, 5),
('guild', 3, 700, 7467, 5),
('guild', 1, 1500, 13405, 14),
('guild', 1, 1500, 1520, 3),
('guild', 2, 1500, 13405, 14),
('guild', 2, 1500, 1520, 3),
('guild', 3, 1500, 7011, 3),
('guild', 3, 1500, 13405, 14),
('guild', 1, 3000, 10201, 10),
('guild', 2, 3000, 10201, 10),
('guild', 3, 3000, 10201, 10),
('guild', 1, 6000, 13895, 14),
('guild', 1, 6000, 1520, 6),
('guild', 2, 6000, 13895, 14),
('guild', 2, 6000, 1520, 6),
('guild', 3, 6000, 13895, 14),
('guild', 3, 6000, 7011, 4),
('guild', 1, 12000, 13406, 14),
('guild', 1, 12000, 1520, 9),
('guild', 2, 12000, 13406, 14),
('guild', 2, 12000, 1520, 9),
('guild', 3, 12000, 13406, 14),
('guild', 3, 12000, 7011, 5),
('guild', 1, 25000, 10207, 10),
('guild', 2, 25000, 10207, 10),
('guild', 3, 25000, 10207, 10),
('guild', 1, 50000, 1520, 12),
('guild', 1, 50000, 13896, 14),
('guild', 2, 50000, 1520, 12),
('guild', 2, 50000, 13896, 14),
('guild', 3, 50000, 7011, 6),
('guild', 3, 50000, 13896, 14),
('guild', 1, 100000, 10201, 10),
('guild', 2, 100000, 10201, 10),
('guild', 3, 100000, 10201, 10),
('guild', 1, 200000, 13406, 16),
('guild', 2, 200000, 13406, 16),
('guild', 3, 200000, 13406, 16),
('guild', 1, 300000, 13896, 16),
('guild', 2, 300000, 13896, 16),
('guild', 3, 300000, 13896, 16),
('guild', 1, 400000, 10207, 10),
('guild', 2, 400000, 10207, 10),
('guild', 3, 400000, 10207, 10),
('guild', 1, 500000, 13407, 6),
('guild', 1, 500000, 13897, 6),
('guild', 2, 500000, 13407, 6),
('guild', 2, 500000, 13897, 6),
('guild', 3, 500000, 13407, 6),
('guild', 3, 500000, 13897, 6);
-- Ripped trials
INSERT INTO public.festa_trials
(objective, goal_id, times_req, locale_req, reward)
VALUES
(1,27,1,0,1),
(5,53034,0,0,400),
(5,22042,0,0,89),
(5,23397,0,0,89),
(1,28,1,0,1),
(1,68,1,0,1),
(1,6,1,0,2),
(1,38,1,0,2),
(1,20,1,0,3),
(1,39,1,0,4),
(1,48,1,0,4),
(1,67,1,0,4),
(1,93,1,0,4),
(1,22,1,0,5),
(1,52,1,0,5),
(1,101,1,0,5),
(1,1,1,0,5),
(1,37,1,0,5),
(1,15,1,0,5),
(1,45,1,0,5),
(1,74,1,0,5),
(1,78,1,0,5),
(1,103,1,0,5),
(1,51,1,0,6),
(1,17,1,0,6),
(1,21,1,0,6),
(1,92,1,0,6),
(1,47,1,0,7),
(1,46,1,0,7),
(1,26,1,0,7),
(1,14,1,0,7),
(1,11,1,0,7),
(1,44,1,0,8),
(1,43,1,0,8),
(1,49,1,0,8),
(1,40,1,0,8),
(1,76,1,0,8),
(1,89,1,0,8),
(1,94,1,0,8),
(1,96,1,0,8),
(1,75,1,0,8),
(1,91,1,0,8),
(1,53,1,0,9),
(1,80,1,0,9),
(1,42,1,0,9),
(1,79,1,0,9),
(1,81,1,0,10),
(1,41,1,0,10),
(1,82,1,0,10),
(1,90,1,0,10),
(1,149,1,0,10),
(1,85,1,0,11),
(1,95,1,0,11),
(1,121,1,0,11),
(1,142,1,0,11),
(1,141,1,0,11),
(1,146,1,0,12),
(1,147,1,0,12),
(1,148,1,0,12),
(1,151,1,0,12),
(1,152,1,0,12),
(1,159,1,0,12),
(1,153,1,0,12),
(1,162,1,0,12),
(1,111,1,0,13),
(1,110,1,0,13),
(1,112,1,0,13),
(1,109,1,0,14),
(1,169,1,0,15),
(2,33,1,0,6),
(2,104,1,0,8),
(2,119,1,0,8),
(2,120,1,0,8),
(2,54,1,0,8),
(2,59,1,0,8),
(2,64,1,0,8),
(2,65,1,0,8),
(2,99,1,0,9),
(2,83,1,0,9),
(2,84,1,0,10),
(2,77,1,0,10),
(2,106,1,0,10),
(2,55,1,0,10),
(2,58,1,0,10),
(2,7,1,0,10),
(2,50,1,0,11),
(2,131,1,0,11),
(2,129,1,0,11),
(2,140,1,0,11),
(2,122,1,0,11),
(2,126,1,0,11),
(2,127,1,0,11),
(2,128,1,0,11),
(2,130,1,0,11),
(2,139,1,0,11),
(2,144,1,0,11),
(2,150,1,0,11),
(2,158,1,0,11),
(2,164,1,0,15),
(2,165,1,0,15),
(2,2,1,7,15),
(2,36,1,0,15),
(2,71,1,0,15),
(2,108,1,0,15),
(2,116,1,0,15),
(2,107,1,0,15),
(2,154,1,0,17),
(2,166,1,0,17),
(2,170,1,0,18),
(3,31,1,0,1),
(3,8,1,0,3),
(3,123,1,0,8),
(3,105,1,0,9),
(3,125,1,0,11),
(3,115,1,0,12),
(3,114,1,0,12),
(3,161,1,0,12),
(4,670,1,0,1),
(4,671,1,0,1),
(4,672,1,0,1),
(4,675,1,0,1),
(4,673,1,0,1),
(4,674,1,0,1);
END;

View File

@@ -0,0 +1,13 @@
BEGIN;
INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity)
VALUES
(1800, 17, 0, 250),
(3600, 17, 0, 500),
(7200, 17, 0, 1000),
(10800, 17, 0, 1500),
(18000, 17, 0, 1750),
(28800, 17, 0, 3000),
(43200, 17, 0, 4000);
END;

View File

@@ -0,0 +1,918 @@
BEGIN;
INSERT INTO public.normal_shop_items
(shoptype, shopid, itemhash, itemid, points, tradequantity, rankreqlow, rankreqhigh, rankreqg, storelevelreq, maximumquantity, boughtquantity, roadfloorsrequired, weeklyfataliskills)
VALUES
(10,6,1,2146,25,1,0,0,1,1,0,1,0,0),
(10,6,2,2147,25,1,0,0,1,1,0,1,0,0),
(10,6,3,2148,25,1,0,0,1,1,0,1,0,0),
(10,6,4,2149,25,1,0,0,1,1,0,1,0,0),
(10,6,5,2150,25,1,0,0,1,1,0,1,0,0),
(10,6,6,2151,25,1,0,0,1,1,0,1,0,0),
(10,6,7,2152,25,1,0,0,1,1,0,1,0,0),
(10,6,8,2153,25,1,0,0,1,1,0,1,0,0),
(10,6,9,2154,25,1,0,0,1,1,0,1,0,0),
(10,6,10,2155,25,1,0,0,1,1,0,1,0,0),
(10,6,11,4398,25,1,0,0,1,1,0,1,0,0),
(10,6,12,12460,25,1,0,0,1,1,0,1,0,0),
(10,6,13,12461,25,1,0,0,1,1,0,1,0,0),
(10,6,14,12462,25,1,0,0,1,1,0,1,0,0),
(10,6,15,12463,25,1,0,0,1,1,0,1,0,0),
(10,6,16,12464,25,1,0,0,1,1,0,1,0,0),
(10,6,17,12465,25,1,0,0,1,1,0,1,0,0),
(10,6,18,12466,25,1,0,0,1,1,0,1,0,0),
(10,6,19,12467,25,1,0,0,1,1,0,1,0,0),
(10,6,20,12468,25,1,0,0,1,1,0,1,0,0),
(10,6,21,12469,25,1,0,0,1,1,0,1,0,0),
(10,6,22,15109,1000,1,0,0,1,1,0,1,0,0),
(10,6,23,15110,1000,1,0,0,1,1,0,1,0,0),
(10,6,24,2158,200,100,0,0,1,1,0,1,0,0),
(10,6,25,12306,2,1,0,0,1,1,0,1,80,0),
(10,6,26,12306,20000,10000,0,0,1,1,0,1,80,0),
(10,4,27,11664,20000,1,0,0,1,1,0,1,0,0),
(10,4,28,11665,20000,1,0,0,1,1,0,1,0,0),
(10,4,29,11666,20000,1,0,0,1,1,0,1,0,0),
(10,4,30,11667,20000,1,0,0,1,1,0,1,0,0),
(10,4,31,11668,20000,1,0,0,1,1,0,1,0,0),
(10,4,32,11669,20000,1,0,0,1,1,0,1,0,0),
(10,4,33,11670,20000,1,0,0,1,1,0,1,0,0),
(10,4,34,11671,20000,1,0,0,1,1,0,1,0,0),
(10,4,35,11672,20000,1,0,0,1,1,0,1,0,0),
(10,4,36,11673,20000,1,0,0,1,1,0,1,0,0),
(10,4,37,11674,20000,1,0,0,1,1,0,1,0,0),
(10,4,38,11675,20000,1,0,0,1,1,0,1,0,0),
(10,4,39,11676,20000,1,0,0,1,1,0,1,0,0),
(10,4,40,11677,20000,1,0,0,1,1,0,1,0,0),
(10,4,41,11678,20000,1,0,0,1,1,0,1,0,0),
(10,4,42,11679,20000,1,0,0,1,1,0,1,0,0),
(10,4,43,11680,20000,1,0,0,1,1,0,1,0,0),
(10,4,44,11681,20000,1,0,0,1,1,0,1,0,0),
(10,4,45,11682,20000,1,0,0,1,1,0,1,0,0),
(10,4,46,11683,20000,1,0,0,1,1,0,1,0,0),
(10,4,47,11684,20000,1,0,0,1,1,0,1,0,0),
(10,4,48,11685,20000,1,0,0,1,1,0,1,0,0),
(10,4,49,11686,20000,1,0,0,1,1,0,1,0,0),
(10,4,50,11687,20000,1,0,0,1,1,0,1,0,0),
(10,4,51,11688,20000,1,0,0,1,1,0,1,0,0),
(10,4,52,11689,20000,1,0,0,1,1,0,1,0,0),
(10,4,53,11690,20000,1,0,0,1,1,0,1,0,0),
(10,4,54,11691,20000,1,0,0,1,1,0,1,0,0),
(10,4,55,11692,20000,1,0,0,1,1,0,1,0,0),
(10,4,56,11693,20000,1,0,0,1,1,0,1,0,0),
(10,4,57,11694,20000,1,0,0,1,1,0,1,0,0),
(10,4,58,11695,20000,1,0,0,1,1,0,1,0,0),
(10,4,59,11696,20000,1,0,0,1,1,0,1,0,0),
(10,4,60,11697,20000,1,0,0,1,1,0,1,0,0),
(10,4,61,12893,20000,1,0,0,1,1,0,1,0,0),
(10,4,62,12894,20000,1,0,0,1,1,0,1,0,0),
(10,4,63,12895,20000,1,0,0,1,1,0,1,0,0),
(10,4,64,12896,20000,1,0,0,1,1,0,1,0,0),
(10,4,65,12897,20000,1,0,0,1,1,0,1,0,0),
(10,4,66,12898,20000,1,0,0,1,1,0,1,0,0),
(10,4,67,12899,20000,1,0,0,1,1,0,1,0,0),
(10,4,68,14337,20000,1,0,0,1,1,0,1,0,0),
(10,4,69,14338,20000,1,0,0,1,1,0,1,0,0),
(10,4,70,14339,20000,1,0,0,1,1,0,1,0,0),
(10,4,71,14340,20000,1,0,0,1,1,0,1,0,0),
(10,4,72,14341,20000,1,0,0,1,1,0,1,0,0),
(10,4,73,14342,20000,1,0,0,1,1,0,1,0,0),
(10,4,74,14343,20000,1,0,0,1,1,0,1,0,0),
(10,4,75,14344,20000,1,0,0,1,1,0,1,0,0),
(10,4,76,14345,20000,1,0,0,1,1,0,1,0,0),
(10,4,77,9254,10000,1,0,0,1,1,0,1,0,0),
(10,4,78,9255,10000,1,0,0,1,1,0,1,0,0),
(10,4,79,9256,10000,1,0,0,1,1,0,1,0,0),
(10,4,80,9257,10000,1,0,0,1,1,0,1,0,0),
(10,4,81,9258,10000,1,0,0,1,1,0,1,0,0),
(10,4,82,9259,10000,1,0,0,1,1,0,1,0,0),
(10,4,83,9260,10000,1,0,0,1,1,0,1,0,0),
(10,4,84,9261,10000,1,0,0,1,1,0,1,0,0),
(10,4,85,9262,10000,1,0,0,1,1,0,1,0,0),
(10,4,86,9263,10000,1,0,0,1,1,0,1,0,0),
(10,4,87,9264,10000,1,0,0,1,1,0,1,0,0),
(10,4,88,9265,10000,1,0,0,1,1,0,1,0,0),
(10,4,89,9266,10000,1,0,0,1,1,0,1,0,0),
(10,4,90,9267,10000,1,0,0,1,1,0,1,0,0),
(10,4,91,9268,10000,1,0,0,1,1,0,1,0,0),
(10,4,92,9269,10000,1,0,0,1,1,0,1,0,0),
(10,4,93,9270,10000,1,0,0,1,1,0,1,0,0),
(10,4,94,9271,10000,1,0,0,1,1,0,1,0,0),
(10,4,95,9272,10000,1,0,0,1,1,0,1,0,0),
(10,4,96,9273,10000,1,0,0,1,1,0,1,0,0),
(10,4,97,9274,10000,1,0,0,1,1,0,1,0,0),
(10,4,98,9275,10000,1,0,0,1,1,0,1,0,0),
(10,4,99,9276,10000,1,0,0,1,1,0,1,0,0),
(10,4,100,9277,10000,1,0,0,1,1,0,1,0,0),
(10,4,101,9278,10000,1,0,0,1,1,0,1,0,0),
(10,4,102,9279,10000,1,0,0,1,1,0,1,0,0),
(10,4,103,9280,10000,1,0,0,1,1,0,1,0,0),
(10,4,104,9281,10000,1,0,0,1,1,0,1,0,0),
(10,4,105,9282,10000,1,0,0,1,1,0,1,0,0),
(10,4,106,9283,10000,1,0,0,1,1,0,1,0,0),
(10,4,107,9284,10000,1,0,0,1,1,0,1,0,0),
(10,4,108,9285,10000,1,0,0,1,1,0,1,0,0),
(10,4,109,9286,10000,1,0,0,1,1,0,1,0,0),
(10,4,110,9287,10000,1,0,0,1,1,0,1,0,0),
(10,4,111,9288,10000,1,0,0,1,1,0,1,0,0),
(10,4,112,9289,10000,1,0,0,1,1,0,1,0,0),
(10,4,113,9290,10000,1,0,0,1,1,0,1,0,0),
(10,4,114,9291,10000,1,0,0,1,1,0,1,0,0),
(10,4,115,9292,10000,1,0,0,1,1,0,1,0,0),
(10,4,116,9293,10000,1,0,0,1,1,0,1,0,0),
(10,4,117,9294,10000,1,0,0,1,1,0,1,0,0),
(10,4,118,9295,10000,1,0,0,1,1,0,1,0,0),
(10,4,119,9296,10000,1,0,0,1,1,0,1,0,0),
(10,4,120,9297,10000,1,0,0,1,1,0,1,0,0),
(10,4,121,9298,10000,1,0,0,1,1,0,1,0,0),
(10,4,122,9299,10000,1,0,0,1,1,0,1,0,0),
(10,4,123,9300,10000,1,0,0,1,1,0,1,0,0),
(10,4,124,9301,10000,1,0,0,1,1,0,1,0,0),
(10,4,125,13196,10000,1,0,0,1,1,0,1,0,0),
(10,4,126,13197,10000,1,0,0,1,1,0,1,0,0),
(10,4,127,13198,10000,1,0,0,1,1,0,1,0,0),
(10,4,128,13199,10000,1,0,0,1,1,0,1,0,0),
(10,4,129,15542,10000,1,0,0,1,1,0,1,0,0),
(10,4,130,15543,10000,1,0,0,1,1,0,1,0,0),
(10,4,131,15544,10000,1,0,0,1,1,0,1,0,0),
(10,4,132,15545,10000,1,0,0,1,1,0,1,0,0),
(10,4,133,13640,20000,1,0,0,1,1,0,1,0,0),
(10,4,134,13641,20000,1,0,0,1,1,0,1,0,0),
(10,4,135,13642,20000,1,0,0,1,1,0,1,0,0),
(10,4,136,13643,20000,1,0,0,1,1,0,1,0,0),
(10,4,137,13644,20000,1,0,0,1,1,0,1,0,0),
(10,4,138,13645,20000,1,0,0,1,1,0,1,0,0),
(10,4,139,13646,20000,1,0,0,1,1,0,1,0,0),
(10,4,140,13647,20000,1,0,0,1,1,0,1,0,0),
(10,4,141,13648,20000,1,0,0,1,1,0,1,0,0),
(10,4,142,13649,20000,1,0,0,1,1,0,1,0,0),
(10,4,143,13650,20000,1,0,0,1,1,0,1,0,0),
(10,4,144,13651,20000,1,0,0,1,1,0,1,0,0),
(10,4,145,13652,20000,1,0,0,1,1,0,1,0,0),
(10,4,146,13653,20000,1,0,0,1,1,0,1,0,0),
(10,4,147,13654,20000,1,0,0,1,1,0,1,0,0),
(10,4,148,13655,20000,1,0,0,1,1,0,1,0,0),
(10,4,149,13656,20000,1,0,0,1,1,0,1,0,0),
(10,4,150,13657,20000,1,0,0,1,1,0,1,0,0),
(10,4,151,13658,20000,1,0,0,1,1,0,1,0,0),
(10,4,152,13659,20000,1,0,0,1,1,0,1,0,0),
(10,4,153,13660,20000,1,0,0,1,1,0,1,0,0),
(10,4,154,13661,20000,1,0,0,1,1,0,1,0,0),
(10,4,155,13662,20000,1,0,0,1,1,0,1,0,0),
(10,4,156,13663,20000,1,0,0,1,1,0,1,0,0),
(10,4,157,13664,20000,1,0,0,1,1,0,1,0,0),
(10,4,158,13665,20000,1,0,0,1,1,0,1,0,0),
(10,4,159,13666,20000,1,0,0,1,1,0,1,0,0),
(10,4,160,13667,20000,1,0,0,1,1,0,1,0,0),
(10,4,161,13668,20000,1,0,0,1,1,0,1,0,0),
(10,4,162,13669,20000,1,0,0,1,1,0,1,0,0),
(10,4,163,13670,20000,1,0,0,1,1,0,1,0,0),
(10,4,164,13671,20000,1,0,0,1,1,0,1,0,0),
(10,4,165,13672,20000,1,0,0,1,1,0,1,0,0),
(10,4,166,13673,20000,1,0,0,1,1,0,1,0,0),
(10,4,167,13674,20000,1,0,0,1,1,0,1,0,0),
(10,4,168,13675,20000,1,0,0,1,1,0,1,0,0),
(10,4,169,13676,20000,1,0,0,1,1,0,1,0,0),
(10,4,170,13677,20000,1,0,0,1,1,0,1,0,0),
(10,4,171,13678,20000,1,0,0,1,1,0,1,0,0),
(10,4,172,13679,20000,1,0,0,1,1,0,1,0,0),
(10,4,173,13680,20000,1,0,0,1,1,0,1,0,0),
(10,4,174,13681,20000,1,0,0,1,1,0,1,0,0),
(10,4,175,13682,20000,1,0,0,1,1,0,1,0,0),
(10,4,176,13683,20000,1,0,0,1,1,0,1,0,0),
(10,4,177,13684,20000,1,0,0,1,1,0,1,0,0),
(10,4,178,13685,20000,1,0,0,1,1,0,1,0,0),
(10,4,179,13686,20000,1,0,0,1,1,0,1,0,0),
(10,4,180,13687,20000,1,0,0,1,1,0,1,0,0),
(10,4,181,13688,20000,1,0,0,1,1,0,1,0,0),
(10,4,182,13689,20000,1,0,0,1,1,0,1,0,0),
(10,4,183,13690,20000,1,0,0,1,1,0,1,0,0),
(10,4,184,13691,20000,1,0,0,1,1,0,1,0,0),
(10,4,185,15546,20000,1,0,0,1,1,0,1,0,0),
(10,4,186,15547,20000,1,0,0,1,1,0,1,0,0),
(10,4,187,15548,20000,1,0,0,1,1,0,1,0,0),
(10,4,188,15549,20000,1,0,0,1,1,0,1,0,0),
(10,4,189,16162,35000,1,0,0,1,1,0,1,0,0),
(10,4,190,16163,35000,1,0,0,1,1,0,1,0,0),
(10,4,191,16164,35000,1,0,0,1,1,0,1,0,0),
(10,4,192,16165,35000,1,0,0,1,1,0,1,0,0),
(10,4,193,16166,35000,1,0,0,1,1,0,1,0,0),
(10,4,194,16167,35000,1,0,0,1,1,0,1,0,0),
(10,4,195,16168,35000,1,0,0,1,1,0,1,0,0),
(10,4,196,16169,35000,1,0,0,1,1,0,1,0,0),
(10,4,197,16172,35000,1,0,0,1,1,0,1,0,0),
(10,4,198,16173,35000,1,0,0,1,1,0,1,0,0),
(10,4,199,16174,35000,1,0,0,1,1,0,1,0,0),
(10,4,200,16175,35000,1,0,0,1,1,0,1,0,0),
(10,4,201,16176,35000,1,0,0,1,1,0,1,0,0),
(10,4,202,16177,35000,1,0,0,1,1,0,1,0,0),
(10,4,203,16178,35000,1,0,0,1,1,0,1,0,0),
(10,4,204,16179,35000,1,0,0,1,1,0,1,0,0),
(10,4,205,16182,35000,1,0,0,1,1,0,1,0,0),
(10,4,206,16183,35000,1,0,0,1,1,0,1,0,0),
(10,4,207,16184,35000,1,0,0,1,1,0,1,0,0),
(10,4,208,16185,35000,1,0,0,1,1,0,1,0,0),
(10,4,209,16186,35000,1,0,0,1,1,0,1,0,0),
(10,4,210,16187,35000,1,0,0,1,1,0,1,0,0),
(10,4,211,16188,35000,1,0,0,1,1,0,1,0,0),
(10,4,212,16189,35000,1,0,0,1,1,0,1,0,0),
(10,4,213,16192,35000,1,0,0,1,1,0,1,0,0),
(10,4,214,16193,35000,1,0,0,1,1,0,1,0,0),
(10,4,215,16194,35000,1,0,0,1,1,0,1,0,0),
(10,4,216,16195,35000,1,0,0,1,1,0,1,0,0),
(10,4,217,16196,35000,1,0,0,1,1,0,1,0,0),
(10,4,218,16197,35000,1,0,0,1,1,0,1,0,0),
(10,4,219,16198,35000,1,0,0,1,1,0,1,0,0),
(10,4,220,16199,35000,1,0,0,1,1,0,1,0,0),
(10,4,221,16202,35000,1,0,0,1,1,0,1,0,0),
(10,4,222,16203,35000,1,0,0,1,1,0,1,0,0),
(10,4,223,16204,35000,1,0,0,1,1,0,1,0,0),
(10,4,224,16205,35000,1,0,0,1,1,0,1,0,0),
(10,4,225,16206,35000,1,0,0,1,1,0,1,0,0),
(10,4,226,16207,35000,1,0,0,1,1,0,1,0,0),
(10,4,227,16208,35000,1,0,0,1,1,0,1,0,0),
(10,4,228,16209,35000,1,0,0,1,1,0,1,0,0),
(10,4,229,16212,35000,1,0,0,1,1,0,1,0,0),
(10,4,230,16213,35000,1,0,0,1,1,0,1,0,0),
(10,4,231,16214,35000,1,0,0,1,1,0,1,0,0),
(10,4,232,16215,35000,1,0,0,1,1,0,1,0,0),
(10,4,233,16216,35000,1,0,0,1,1,0,1,0,0),
(10,4,234,16217,35000,1,0,0,1,1,0,1,0,0),
(10,4,235,16218,35000,1,0,0,1,1,0,1,0,0),
(10,4,236,16219,35000,1,0,0,1,1,0,1,0,0),
(10,4,237,16222,35000,1,0,0,1,1,0,1,0,0),
(10,4,238,16223,35000,1,0,0,1,1,0,1,0,0),
(10,4,239,16224,35000,1,0,0,1,1,0,1,0,0),
(10,4,240,16225,35000,1,0,0,1,1,0,1,0,0),
(10,4,241,16226,35000,1,0,0,1,1,0,1,0,0),
(10,4,242,16227,35000,1,0,0,1,1,0,1,0,0),
(10,4,243,16228,35000,1,0,0,1,1,0,1,0,0),
(10,4,244,16229,35000,1,0,0,1,1,0,1,0,0),
(10,4,245,16232,35000,1,0,0,1,1,0,1,0,0),
(10,4,246,16233,35000,1,0,0,1,1,0,1,0,0),
(10,4,247,16234,35000,1,0,0,1,1,0,1,0,0),
(10,4,248,16235,35000,1,0,0,1,1,0,1,0,0),
(10,4,249,16236,35000,1,0,0,1,1,0,1,0,0),
(10,4,250,16237,35000,1,0,0,1,1,0,1,0,0),
(10,4,251,16238,35000,1,0,0,1,1,0,1,0,0),
(10,4,252,16239,35000,1,0,0,1,1,0,1,0,0),
(10,4,253,16242,35000,1,0,0,1,1,0,1,0,0),
(10,4,254,16243,35000,1,0,0,1,1,0,1,0,0),
(10,4,255,16244,35000,1,0,0,1,1,0,1,0,0),
(10,4,256,16245,35000,1,0,0,1,1,0,1,0,0),
(10,4,257,16246,35000,1,0,0,1,1,0,1,0,0),
(10,4,258,16247,35000,1,0,0,1,1,0,1,0,0),
(10,4,259,16248,35000,1,0,0,1,1,0,1,0,0),
(10,4,260,16249,35000,1,0,0,1,1,0,1,0,0),
(10,4,261,16252,35000,1,0,0,1,1,0,1,0,0),
(10,4,262,16253,35000,1,0,0,1,1,0,1,0,0),
(10,4,263,16254,35000,1,0,0,1,1,0,1,0,0),
(10,4,264,16255,35000,1,0,0,1,1,0,1,0,0),
(10,4,265,16256,35000,1,0,0,1,1,0,1,0,0),
(10,4,266,16257,35000,1,0,0,1,1,0,1,0,0),
(10,4,267,16258,35000,1,0,0,1,1,0,1,0,0),
(10,4,268,16259,35000,1,0,0,1,1,0,1,0,0),
(10,4,269,16262,35000,1,0,0,1,1,0,1,0,0),
(10,4,270,16263,35000,1,0,0,1,1,0,1,0,0),
(10,4,271,16264,35000,1,0,0,1,1,0,1,0,0),
(10,4,272,16265,35000,1,0,0,1,1,0,1,0,0),
(10,4,273,16266,35000,1,0,0,1,1,0,1,0,0),
(10,4,274,16267,35000,1,0,0,1,1,0,1,0,0),
(10,4,275,16268,35000,1,0,0,1,1,0,1,0,0),
(10,4,276,16269,35000,1,0,0,1,1,0,1,0,0),
(10,4,277,16272,35000,1,0,0,1,1,0,1,0,0),
(10,4,278,16273,35000,1,0,0,1,1,0,1,0,0),
(10,4,279,16274,35000,1,0,0,1,1,0,1,0,0),
(10,4,280,16275,35000,1,0,0,1,1,0,1,0,0),
(10,4,281,16276,35000,1,0,0,1,1,0,1,0,0),
(10,4,282,16277,35000,1,0,0,1,1,0,1,0,0),
(10,4,283,16278,35000,1,0,0,1,1,0,1,0,0),
(10,4,284,16279,35000,1,0,0,1,1,0,1,0,0),
(10,4,285,16282,35000,1,0,0,1,1,0,1,0,0),
(10,4,286,16283,35000,1,0,0,1,1,0,1,0,0),
(10,4,287,16284,35000,1,0,0,1,1,0,1,0,0),
(10,4,288,16285,35000,1,0,0,1,1,0,1,0,0),
(10,4,289,16286,35000,1,0,0,1,1,0,1,0,0),
(10,4,290,16287,35000,1,0,0,1,1,0,1,0,0),
(10,4,291,16288,35000,1,0,0,1,1,0,1,0,0),
(10,4,292,16289,35000,1,0,0,1,1,0,1,0,0),
(10,4,293,16292,35000,1,0,0,1,1,0,1,0,0),
(10,4,294,16293,35000,1,0,0,1,1,0,1,0,0),
(10,4,295,16294,35000,1,0,0,1,1,0,1,0,0),
(10,4,296,16295,35000,1,0,0,1,1,0,1,0,0),
(10,4,297,16296,35000,1,0,0,1,1,0,1,0,0),
(10,4,298,16297,35000,1,0,0,1,1,0,1,0,0),
(10,4,299,16298,35000,1,0,0,1,1,0,1,0,0),
(10,4,300,16299,35000,1,0,0,1,1,0,1,0,0),
(10,8,301,14136,15000,1,0,0,1,1,0,1,0,0),
(10,8,302,14137,15000,1,0,0,1,1,0,1,0,0),
(10,8,303,14138,15000,1,0,0,1,1,0,1,0,0),
(10,8,304,14139,15000,1,0,0,1,1,0,1,0,0),
(10,8,305,14140,15000,1,0,0,1,1,0,1,0,0),
(10,8,306,14141,15000,1,0,0,1,1,0,1,0,0),
(10,8,307,14142,15000,1,0,0,1,1,0,1,0,0),
(10,8,308,14143,15000,1,0,0,1,1,0,1,0,0),
(10,8,309,14144,15000,1,0,0,1,1,0,1,0,0),
(10,8,310,14145,15000,1,0,0,1,1,0,1,0,0),
(10,8,311,14454,30000,1,0,0,1,1,0,1,0,0),
(10,8,312,14455,30000,1,0,0,1,1,0,1,0,0),
(10,8,313,14456,30000,1,0,0,1,1,0,1,0,0),
(10,8,314,14457,30000,1,0,0,1,1,0,1,0,0),
(10,8,315,14458,30000,1,0,0,1,1,0,1,0,0),
(10,8,316,14459,30000,1,0,0,1,1,0,1,0,0),
(10,8,317,14460,30000,1,0,0,1,1,0,1,0,0),
(10,8,318,14461,30000,1,0,0,1,1,0,1,0,0),
(10,8,319,14462,30000,1,0,0,1,1,0,1,0,0),
(10,8,320,14463,30000,1,0,0,1,1,0,1,0,0),
(10,8,321,12724,50000,1,0,0,1,1,0,1,0,0),
(10,8,322,12725,50000,1,0,0,1,1,0,1,0,0),
(10,8,323,12726,50000,1,0,0,1,1,0,1,0,0),
(10,8,324,12727,50000,1,0,0,1,1,0,1,0,0),
(10,8,325,12728,50000,1,0,0,1,1,0,1,0,0),
(10,8,326,12729,50000,1,0,0,1,1,0,1,0,0),
(10,8,327,12730,50000,1,0,0,1,1,0,1,0,0),
(10,8,328,12731,50000,1,0,0,1,1,0,1,0,0),
(10,8,329,12732,50000,1,0,0,1,1,0,1,0,0),
(10,8,330,12733,50000,1,0,0,1,1,0,1,0,0),
(10,8,331,12734,50000,1,0,0,1,1,0,1,0,0),
(10,8,332,12735,50000,1,0,0,1,1,0,1,0,0),
(10,8,333,12736,50000,1,0,0,1,1,0,1,0,0),
(10,8,334,12737,50000,1,0,0,1,1,0,1,0,0),
(10,8,335,12738,50000,1,0,0,1,1,0,1,0,0),
(10,8,336,12739,50000,1,0,0,1,1,0,1,0,0),
(10,8,337,12740,50000,1,0,0,1,1,0,1,0,0),
(10,8,338,12741,50000,1,0,0,1,1,0,1,0,0),
(10,8,339,12742,50000,1,0,0,1,1,0,1,0,0),
(10,8,340,12743,50000,1,0,0,1,1,0,1,0,0),
(10,8,341,12744,50000,1,0,0,1,1,0,1,0,0),
(10,8,342,12745,50000,1,0,0,1,1,0,1,0,0),
(10,8,343,12746,50000,1,0,0,1,1,0,1,0,0),
(10,8,344,12747,50000,1,0,0,1,1,0,1,0,0),
(10,8,345,12748,50000,1,0,0,1,1,0,1,0,0),
(10,8,346,12749,50000,1,0,0,1,1,0,1,0,0),
(10,8,347,12750,50000,1,0,0,1,1,0,1,0,0),
(10,8,348,12751,50000,1,0,0,1,1,0,1,0,0),
(10,8,349,12752,50000,1,0,0,1,1,0,1,0,0),
(10,8,350,12753,50000,1,0,0,1,1,0,1,0,0),
(10,8,351,15070,50000,1,0,0,1,1,0,1,0,0),
(10,8,352,15071,50000,1,0,0,1,1,0,1,0,0),
(10,8,353,15072,50000,1,0,0,1,1,0,1,0,0),
(10,8,354,15073,50000,1,0,0,1,1,0,1,0,0),
(10,8,355,15074,50000,1,0,0,1,1,0,1,0,0),
(10,8,356,15075,50000,1,0,0,1,1,0,1,0,0),
(10,8,357,15076,50000,1,0,0,1,1,0,1,0,0),
(10,8,358,15077,50000,1,0,0,1,1,0,1,0,0),
(10,8,359,15078,50000,1,0,0,1,1,0,1,0,0),
(10,8,360,15079,50000,1,0,0,1,1,0,1,0,0),
(10,8,361,15567,20000,1,0,0,1,1,0,1,0,0),
(10,8,362,15568,20000,1,0,0,1,1,0,1,0,0),
(10,8,363,15569,20000,1,0,0,1,1,0,1,0,0),
(10,8,364,15570,20000,1,0,0,1,1,0,1,0,0),
(10,8,365,15571,20000,1,0,0,1,1,0,1,0,0),
(10,8,366,15572,20000,1,0,0,1,1,0,1,0,0),
(10,8,367,15573,20000,1,0,0,1,1,0,1,0,0),
(10,8,368,15574,20000,1,0,0,1,1,0,1,0,0),
(10,8,369,15575,20000,1,0,0,1,1,0,1,0,0),
(10,8,370,15576,20000,1,0,0,1,1,0,1,0,0),
(10,8,371,15577,20000,1,0,0,1,1,0,1,0,0),
(10,8,372,15578,20000,1,0,0,1,1,0,1,0,0),
(10,8,373,15579,20000,1,0,0,1,1,0,1,0,0),
(10,8,374,15580,20000,1,0,0,1,1,0,1,0,0),
(10,8,375,15581,20000,1,0,0,1,1,0,1,0,0),
(10,8,376,15582,20000,1,0,0,1,1,0,1,0,0),
(10,8,377,15583,20000,1,0,0,1,1,0,1,0,0),
(10,8,378,15584,20000,1,0,0,1,1,0,1,0,0),
(10,8,379,15585,20000,1,0,0,1,1,0,1,0,0),
(10,8,380,15586,20000,1,0,0,1,1,0,1,0,0),
(10,8,381,15587,20000,1,0,0,1,1,0,1,0,0),
(10,8,382,15588,20000,1,0,0,1,1,0,1,0,0),
(10,8,383,15589,20000,1,0,0,1,1,0,1,0,0),
(10,8,384,15590,20000,1,0,0,1,1,0,1,0,0),
(10,8,385,15591,20000,1,0,0,1,1,0,1,0,0),
(10,8,386,15592,20000,1,0,0,1,1,0,1,0,0),
(10,8,387,15593,20000,1,0,0,1,1,0,1,0,0),
(10,8,388,15594,20000,1,0,0,1,1,0,1,0,0),
(10,8,389,15595,20000,1,0,0,1,1,0,1,0,0),
(10,8,390,15596,20000,1,0,0,1,1,0,1,0,0),
(10,8,391,15597,20000,1,0,0,1,1,0,1,0,0),
(10,8,392,15598,20000,1,0,0,1,1,0,1,0,0),
(10,8,393,15599,20000,1,0,0,1,1,0,1,0,0),
(10,8,394,15600,20000,1,0,0,1,1,0,1,0,0),
(10,8,395,15601,20000,1,0,0,1,1,0,1,0,0),
(10,8,396,15602,20000,1,0,0,1,1,0,1,0,0),
(10,8,397,15603,20000,1,0,0,1,1,0,1,0,0),
(10,8,398,15604,20000,1,0,0,1,1,0,1,0,0),
(10,8,399,15605,20000,1,0,0,1,1,0,1,0,0),
(10,8,400,15606,20000,1,0,0,1,1,0,1,0,0),
(10,8,401,15607,20000,1,0,0,1,1,0,1,0,0),
(10,8,402,15608,20000,1,0,0,1,1,0,1,0,0),
(10,8,403,15609,20000,1,0,0,1,1,0,1,0,0),
(10,8,404,15610,20000,1,0,0,1,1,0,1,0,0),
(10,8,405,15611,20000,1,0,0,1,1,0,1,0,0),
(10,8,406,15612,20000,1,0,0,1,1,0,1,0,0),
(10,8,407,15613,20000,1,0,0,1,1,0,1,0,0),
(10,8,408,15614,20000,1,0,0,1,1,0,1,0,0),
(10,8,409,15615,20000,1,0,0,1,1,0,1,0,0),
(10,8,410,15616,20000,1,0,0,1,1,0,1,0,0),
(10,8,411,15617,20000,1,0,0,1,1,0,1,0,0),
(10,8,412,15618,20000,1,0,0,1,1,0,1,0,0),
(10,8,413,15619,20000,1,0,0,1,1,0,1,0,0),
(10,8,414,15620,20000,1,0,0,1,1,0,1,0,0),
(10,8,415,15621,20000,1,0,0,1,1,0,1,0,0),
(10,8,416,15622,20000,1,0,0,1,1,0,1,0,0),
(10,8,417,15623,20000,1,0,0,1,1,0,1,0,0),
(10,8,418,15624,20000,1,0,0,1,1,0,1,0,0),
(10,8,419,15625,20000,1,0,0,1,1,0,1,0,0),
(10,8,420,15626,20000,1,0,0,1,1,0,1,0,0),
(10,8,421,15627,20000,1,0,0,1,1,0,1,0,0),
(10,8,422,15628,20000,1,0,0,1,1,0,1,0,0),
(10,8,423,15629,20000,1,0,0,1,1,0,1,0,0),
(10,8,424,15630,20000,1,0,0,1,1,0,1,0,0),
(10,8,425,15631,20000,1,0,0,1,1,0,1,0,0),
(10,8,426,15632,20000,1,0,0,1,1,0,1,0,0),
(10,8,427,15633,20000,1,0,0,1,1,0,1,0,0),
(10,8,428,15634,20000,1,0,0,1,1,0,1,0,0),
(10,8,429,15635,20000,1,0,0,1,1,0,1,0,0),
(10,8,430,15636,20000,1,0,0,1,1,0,1,0,0),
(10,8,431,15637,20000,1,0,0,1,1,0,1,0,0),
(10,8,432,15638,20000,1,0,0,1,1,0,1,0,0),
(10,8,433,15639,20000,1,0,0,1,1,0,1,0,0),
(10,8,434,15640,20000,1,0,0,1,1,0,1,0,0),
(10,8,435,15641,20000,1,0,0,1,1,0,1,0,0),
(10,8,436,15642,20000,1,0,0,1,1,0,1,0,0),
(10,8,437,15643,20000,1,0,0,1,1,0,1,0,0),
(10,8,438,15644,20000,1,0,0,1,1,0,1,0,0),
(10,8,439,15645,20000,1,0,0,1,1,0,1,0,0),
(10,8,440,15646,20000,1,0,0,1,1,0,1,0,0),
(10,8,441,15647,20000,1,0,0,1,1,0,1,0,0),
(10,8,442,15648,20000,1,0,0,1,1,0,1,0,0),
(10,8,443,15649,20000,1,0,0,1,1,0,1,0,0),
(10,8,444,15650,20000,1,0,0,1,1,0,1,0,0),
(10,8,445,15651,20000,1,0,0,1,1,0,1,0,0),
(10,8,446,15652,20000,1,0,0,1,1,0,1,0,0),
(10,8,447,15653,20000,1,0,0,1,1,0,1,0,0),
(10,8,448,15654,20000,1,0,0,1,1,0,1,0,0),
(10,8,449,15655,20000,1,0,0,1,1,0,1,0,0),
(10,8,450,15656,20000,1,0,0,1,1,0,1,0,0),
(10,8,451,15657,20000,1,0,0,1,1,0,1,0,0),
(10,8,452,15658,20000,1,0,0,1,1,0,1,0,0),
(10,8,453,15659,20000,1,0,0,1,1,0,1,0,0),
(10,8,454,15660,20000,1,0,0,1,1,0,1,0,0),
(10,8,455,15661,20000,1,0,0,1,1,0,1,0,0),
(10,8,456,15662,20000,1,0,0,1,1,0,1,0,0),
(10,8,457,15663,20000,1,0,0,1,1,0,1,0,0),
(10,8,458,15664,20000,1,0,0,1,1,0,1,0,0),
(10,8,459,15665,20000,1,0,0,1,1,0,1,0,0),
(10,8,460,15666,20000,1,0,0,1,1,0,1,0,0),
(10,8,461,15667,20000,1,0,0,1,1,0,1,0,0),
(10,8,462,15668,20000,1,0,0,1,1,0,1,0,0),
(10,8,463,15669,20000,1,0,0,1,1,0,1,0,0),
(10,8,464,15670,20000,1,0,0,1,1,0,1,0,0),
(10,8,465,15671,20000,1,0,0,1,1,0,1,0,0),
(10,8,466,15672,20000,1,0,0,1,1,0,1,0,0),
(10,8,467,15673,20000,1,0,0,1,1,0,1,0,0),
(10,8,468,15674,20000,1,0,0,1,1,0,1,0,0),
(10,8,469,15675,20000,1,0,0,1,1,0,1,0,0),
(10,8,470,15676,20000,1,0,0,1,1,0,1,0,0),
(10,8,471,15677,20000,1,0,0,1,1,0,1,0,0),
(10,8,472,15678,20000,1,0,0,1,1,0,1,0,0),
(10,8,473,15679,20000,1,0,0,1,1,0,1,0,0),
(10,8,474,15680,20000,1,0,0,1,1,0,1,0,0),
(10,8,475,15681,20000,1,0,0,1,1,0,1,0,0),
(10,8,476,15682,20000,1,0,0,1,1,0,1,0,0),
(10,8,477,15683,20000,1,0,0,1,1,0,1,0,0),
(10,8,478,15684,20000,1,0,0,1,1,0,1,0,0),
(10,8,479,15685,20000,1,0,0,1,1,0,1,0,0),
(10,8,480,15686,20000,1,0,0,1,1,0,1,0,0),
(10,8,481,15687,20000,1,0,0,1,1,0,1,0,0),
(10,8,482,15688,20000,1,0,0,1,1,0,1,0,0),
(10,8,483,15689,20000,1,0,0,1,1,0,1,0,0),
(10,8,484,15690,20000,1,0,0,1,1,0,1,0,0),
(10,8,485,15691,20000,1,0,0,1,1,0,1,0,0),
(10,8,486,15692,20000,1,0,0,1,1,0,1,0,0),
(10,8,487,15693,20000,1,0,0,1,1,0,1,0,0),
(10,8,488,15694,20000,1,0,0,1,1,0,1,0,0),
(10,8,489,15695,20000,1,0,0,1,1,0,1,0,0),
(10,8,490,15696,20000,1,0,0,1,1,0,1,0,0),
(10,8,491,15697,20000,1,0,0,1,1,0,1,0,0),
(10,8,492,15698,20000,1,0,0,1,1,0,1,0,0),
(10,8,493,15699,20000,1,0,0,1,1,0,1,0,0),
(10,8,494,15700,20000,1,0,0,1,1,0,1,0,0),
(10,8,495,15701,20000,1,0,0,1,1,0,1,0,0),
(10,8,496,15702,20000,1,0,0,1,1,0,1,0,0),
(10,8,497,15703,20000,1,0,0,1,1,0,1,0,0),
(10,8,498,15704,20000,1,0,0,1,1,0,1,0,0),
(10,8,499,15705,20000,1,0,0,1,1,0,1,0,0),
(10,8,500,15706,20000,1,0,0,1,1,0,1,0,0),
(10,8,501,15707,20000,1,0,0,1,1,0,1,0,0),
(10,8,502,15708,20000,1,0,0,1,1,0,1,0,0),
(10,8,503,15709,20000,1,0,0,1,1,0,1,0,0),
(10,8,504,15710,20000,1,0,0,1,1,0,1,0,0),
(10,8,505,15711,20000,1,0,0,1,1,0,1,0,0),
(10,8,506,15712,20000,1,0,0,1,1,0,1,0,0),
(10,8,507,15713,20000,1,0,0,1,1,0,1,0,0),
(10,8,508,15714,20000,1,0,0,1,1,0,1,0,0),
(10,8,509,15715,20000,1,0,0,1,1,0,1,0,0),
(10,8,510,15716,20000,1,0,0,1,1,0,1,0,0),
(10,8,511,15717,20000,1,0,0,1,1,0,1,0,0),
(10,8,512,15718,20000,1,0,0,1,1,0,1,0,0),
(10,8,513,15719,20000,1,0,0,1,1,0,1,0,0),
(10,8,514,15720,20000,1,0,0,1,1,0,1,0,0),
(10,8,515,15721,20000,1,0,0,1,1,0,1,0,0),
(10,8,516,15722,20000,1,0,0,1,1,0,1,0,0),
(10,8,517,15723,20000,1,0,0,1,1,0,1,0,0),
(10,8,518,15724,20000,1,0,0,1,1,0,1,0,0),
(10,8,519,15725,20000,1,0,0,1,1,0,1,0,0),
(10,8,520,15726,20000,1,0,0,1,1,0,1,0,0),
(10,8,521,15727,20000,1,0,0,1,1,0,1,0,0),
(10,8,522,15728,20000,1,0,0,1,1,0,1,0,0),
(10,8,523,15729,20000,1,0,0,1,1,0,1,0,0),
(10,8,524,15730,20000,1,0,0,1,1,0,1,0,0),
(10,8,525,15731,20000,1,0,0,1,1,0,1,0,0),
(10,8,526,15732,20000,1,0,0,1,1,0,1,0,0),
(10,8,527,15733,20000,1,0,0,1,1,0,1,0,0),
(10,8,528,15734,20000,1,0,0,1,1,0,1,0,0),
(10,8,529,15735,20000,1,0,0,1,1,0,1,0,0),
(10,8,530,15736,20000,1,0,0,1,1,0,1,0,0),
(10,8,531,15737,20000,1,0,0,1,1,0,1,0,0),
(10,8,532,15738,20000,1,0,0,1,1,0,1,0,0),
(10,8,533,15739,20000,1,0,0,1,1,0,1,0,0),
(10,8,534,15740,20000,1,0,0,1,1,0,1,0,0),
(10,8,535,15741,20000,1,0,0,1,1,0,1,0,0),
(10,8,536,15742,20000,1,0,0,1,1,0,1,0,0),
(10,8,537,15743,20000,1,0,0,1,1,0,1,0,0),
(10,8,538,15744,20000,1,0,0,1,1,0,1,0,0),
(10,8,539,15745,20000,1,0,0,1,1,0,1,0,0),
(10,8,540,15746,20000,1,0,0,1,1,0,1,0,0),
(10,8,541,15747,20000,1,0,0,1,1,0,1,0,0),
(10,8,542,15748,20000,1,0,0,1,1,0,1,0,0),
(10,8,543,15749,20000,1,0,0,1,1,0,1,0,0),
(10,8,544,15750,20000,1,0,0,1,1,0,1,0,0),
(10,8,545,15751,20000,1,0,0,1,1,0,1,0,0),
(10,8,546,15752,20000,1,0,0,1,1,0,1,0,0),
(10,8,547,15753,20000,1,0,0,1,1,0,1,0,0),
(10,8,548,15754,20000,1,0,0,1,1,0,1,0,0),
(10,8,549,15755,20000,1,0,0,1,1,0,1,0,0),
(10,8,550,15756,20000,1,0,0,1,1,0,1,0,0),
(10,8,551,15757,20000,1,0,0,1,1,0,1,0,0),
(10,8,552,15758,20000,1,0,0,1,1,0,1,0,0),
(10,8,553,15759,20000,1,0,0,1,1,0,1,0,0),
(10,8,554,15760,20000,1,0,0,1,1,0,1,0,0),
(10,8,555,15761,20000,1,0,0,1,1,0,1,0,0),
(10,8,556,15762,20000,1,0,0,1,1,0,1,0,0),
(10,8,557,15763,20000,1,0,0,1,1,0,1,0,0),
(10,8,558,15764,20000,1,0,0,1,1,0,1,0,0),
(10,8,559,15765,20000,1,0,0,1,1,0,1,0,0),
(10,8,560,15766,20000,1,0,0,1,1,0,1,0,0),
(10,8,561,15919,20000,1,0,0,1,1,0,1,0,0),
(10,8,562,15920,20000,1,0,0,1,1,0,1,0,0),
(10,8,563,15921,20000,1,0,0,1,1,0,1,0,0),
(10,8,564,15922,20000,1,0,0,1,1,0,1,0,0),
(10,8,565,15923,20000,1,0,0,1,1,0,1,0,0),
(10,8,566,15924,20000,1,0,0,1,1,0,1,0,0),
(10,8,567,15925,20000,1,0,0,1,1,0,1,0,0),
(10,8,568,15926,20000,1,0,0,1,1,0,1,0,0),
(10,8,569,15927,20000,1,0,0,1,1,0,1,0,0),
(10,8,570,15928,20000,1,0,0,1,1,0,1,0,0),
(10,8,571,15929,20000,1,0,0,1,1,0,1,0,0),
(10,8,572,15930,20000,1,0,0,1,1,0,1,0,0),
(10,8,573,15931,20000,1,0,0,1,1,0,1,0,0),
(10,8,574,15932,20000,1,0,0,1,1,0,1,0,0),
(10,8,575,15933,20000,1,0,0,1,1,0,1,0,0),
(10,8,576,15934,20000,1,0,0,1,1,0,1,0,0),
(10,8,577,15935,20000,1,0,0,1,1,0,1,0,0),
(10,8,578,15936,20000,1,0,0,1,1,0,1,0,0),
(10,8,579,15937,20000,1,0,0,1,1,0,1,0,0),
(10,8,580,15938,20000,1,0,0,1,1,0,1,0,0),
(10,8,581,15939,20000,1,0,0,1,1,0,1,0,0),
(10,8,582,15940,20000,1,0,0,1,1,0,1,0,0),
(10,8,583,15941,20000,1,0,0,1,1,0,1,0,0),
(10,8,584,15942,20000,1,0,0,1,1,0,1,0,0),
(10,8,585,15943,20000,1,0,0,1,1,0,1,0,0),
(10,8,586,15944,20000,1,0,0,1,1,0,1,0,0),
(10,8,587,15945,20000,1,0,0,1,1,0,1,0,0),
(10,8,588,15946,20000,1,0,0,1,1,0,1,0,0),
(10,8,589,15947,20000,1,0,0,1,1,0,1,0,0),
(10,8,590,15948,20000,1,0,0,1,1,0,1,0,0),
(10,8,591,15949,20000,1,0,0,1,1,0,1,0,0),
(10,8,592,15950,20000,1,0,0,1,1,0,1,0,0),
(10,8,593,15951,20000,1,0,0,1,1,0,1,0,0),
(10,8,594,15952,20000,1,0,0,1,1,0,1,0,0),
(10,8,595,15953,20000,1,0,0,1,1,0,1,0,0),
(10,8,596,15954,20000,1,0,0,1,1,0,1,0,0),
(10,8,597,15955,20000,1,0,0,1,1,0,1,0,0),
(10,8,598,15956,20000,1,0,0,1,1,0,1,0,0),
(10,8,599,15957,20000,1,0,0,1,1,0,1,0,0),
(10,8,600,15958,20000,1,0,0,1,1,0,1,0,0),
(10,8,601,15959,20000,1,0,0,1,1,0,1,0,0),
(10,8,602,15960,20000,1,0,0,1,1,0,1,0,0),
(10,8,603,15961,20000,1,0,0,1,1,0,1,0,0),
(10,8,604,15962,20000,1,0,0,1,1,0,1,0,0),
(10,8,605,15963,20000,1,0,0,1,1,0,1,0,0),
(10,8,606,15964,20000,1,0,0,1,1,0,1,0,0),
(10,8,607,15965,20000,1,0,0,1,1,0,1,0,0),
(10,8,608,15966,20000,1,0,0,1,1,0,1,0,0),
(10,8,609,15967,20000,1,0,0,1,1,0,1,0,0),
(10,8,610,15968,20000,1,0,0,1,1,0,1,0,0),
(10,7,611,13506,250,1,0,0,1,1,0,1,50,0),
(10,7,612,15011,250,1,0,0,1,1,0,1,50,0),
(10,7,613,13636,250,1,0,0,1,1,0,1,50,0),
(10,7,614,1227,250,1,0,0,1,1,0,1,50,0),
(10,7,615,15022,250,1,0,0,1,1,0,1,50,0),
(10,8,616,4407,1000,1,0,0,1,1,0,1,0,0),
(10,8,617,4408,1000,1,0,0,1,1,0,1,0,0),
(10,8,618,4409,1000,1,0,0,1,1,0,1,0,0),
(10,8,619,4410,1000,1,0,0,1,1,0,1,0,0),
(10,8,620,4411,1000,1,0,0,1,1,0,1,0,0),
(10,8,621,4412,1000,1,0,0,1,1,0,1,0,0),
(10,8,622,4413,1000,1,0,0,1,1,0,1,0,0),
(10,8,623,4414,1000,1,0,0,1,1,0,1,0,0),
(10,8,624,4823,1000,1,0,0,1,1,0,1,0,0),
(10,8,625,4824,1000,1,0,0,1,1,0,1,0,0),
(10,8,626,4825,1000,1,0,0,1,1,0,1,0,0),
(10,8,627,4826,1000,1,0,0,1,1,0,1,0,0),
(10,8,628,4827,1000,1,0,0,1,1,0,1,0,0),
(10,8,629,4828,1000,1,0,0,1,1,0,1,0,0),
(10,8,630,4829,1000,1,0,0,1,1,0,1,0,0),
(10,8,631,4830,1000,1,0,0,1,1,0,1,0,0),
(10,8,632,5194,1000,1,0,0,1,1,0,1,0,0),
(10,8,633,5195,1000,1,0,0,1,1,0,1,0,0),
(10,8,634,5196,1000,1,0,0,1,1,0,1,0,0),
(10,8,635,5197,1000,1,0,0,1,1,0,1,0,0),
(10,8,636,5198,1000,1,0,0,1,1,0,1,0,0),
(10,8,637,5199,1000,1,0,0,1,1,0,1,0,0),
(10,8,638,5200,1000,1,0,0,1,1,0,1,0,0),
(10,8,639,5201,1000,1,0,0,1,1,0,1,0,0),
(10,8,640,13630,1000,1,0,0,1,1,0,1,0,0),
(10,8,641,13631,1000,1,0,0,1,1,0,1,0,0),
(10,8,642,13632,1000,1,0,0,1,1,0,1,0,0),
(10,8,643,13633,1000,1,0,0,1,1,0,1,0,0),
(10,8,644,13634,1000,1,0,0,1,1,0,1,0,0),
(10,8,645,13635,1000,1,0,0,1,1,0,1,0,0),
(10,8,646,15103,1000,1,0,0,1,1,0,1,0,0),
(10,8,647,15104,1000,1,0,0,1,1,0,1,0,0),
(10,8,648,15105,1000,1,0,0,1,1,0,1,0,0),
(10,8,649,15106,1000,1,0,0,1,1,0,1,0,0),
(10,8,650,15107,1000,1,0,0,1,1,0,1,0,0),
(10,8,651,15108,1000,1,0,0,1,1,0,1,0,0),
(10,8,652,16459,1000,1,0,0,1,1,0,1,0,0),
(10,8,653,16460,1000,1,0,0,1,1,0,1,0,0),
(10,8,654,16461,1000,1,0,0,1,1,0,1,0,0),
(10,8,655,16462,1000,1,0,0,1,1,0,1,0,0),
(10,8,656,16463,1000,1,0,0,1,1,0,1,0,0),
(10,8,657,16464,1000,1,0,0,1,1,0,1,0,0),
(10,8,658,16465,1000,1,0,0,1,1,0,1,0,0),
(10,8,659,16466,1000,1,0,0,1,1,0,1,0,0),
(10,8,660,16467,1000,1,0,0,1,1,0,1,0,0),
(10,8,661,16468,1000,1,0,0,1,1,0,1,0,0),
(10,8,662,16469,1000,1,0,0,1,1,0,1,0,0),
(10,8,663,16470,1000,1,0,0,1,1,0,1,0,0),
(10,8,664,16471,1000,1,0,0,1,1,0,1,0,0),
(10,8,665,16472,1000,1,0,0,1,1,0,1,0,0),
(10,8,666,13416,1000,1,0,0,1,1,0,1,0,0),
(10,8,667,13417,1000,1,0,0,1,1,0,1,0,0),
(10,8,668,13418,1000,1,0,0,1,1,0,1,0,0),
(10,8,669,13419,1000,1,0,0,1,1,0,1,0,0),
(10,8,670,13420,1000,1,0,0,1,1,0,1,0,0),
(10,8,671,14283,1000,1,0,0,1,1,0,1,0,0),
(10,8,672,14284,1000,1,0,0,1,1,0,1,0,0),
(10,8,673,14285,1000,1,0,0,1,1,0,1,0,0),
(10,8,674,14286,1000,1,0,0,1,1,0,1,0,0),
(10,8,675,13182,1000,1,0,0,1,1,0,1,0,0),
(10,8,676,13507,1000,1,0,0,1,1,0,1,0,0),
(10,8,677,13981,1000,1,0,0,1,1,0,1,0,0),
(10,8,678,14744,1000,1,0,0,1,1,0,1,0,0),
(10,8,679,14893,1000,1,0,0,1,1,0,1,0,0),
(10,8,680,15785,1000,1,0,0,1,1,0,1,0,0),
(10,8,681,16419,1000,1,0,0,1,1,0,1,0,0),
(10,8,682,11470,1000,1,0,0,1,1,0,1,0,0),
(10,8,683,12512,1000,1,0,0,1,1,0,1,0,0),
(10,8,684,12884,1000,1,0,0,1,1,0,1,0,0),
(10,8,685,12513,1000,1,0,0,1,1,0,1,0,0),
(10,8,686,12514,1000,1,0,0,1,1,0,1,0,0),
(10,8,687,12515,1000,1,0,0,1,1,0,1,0,0),
(10,8,688,12516,1000,1,0,0,1,1,0,1,0,0),
(10,8,689,12517,1000,1,0,0,1,1,0,1,0,0),
(10,8,690,12518,1000,1,0,0,1,1,0,1,0,0),
(10,8,691,12519,1000,1,0,0,1,1,0,1,0,0),
(10,8,692,12520,1000,1,0,0,1,1,0,1,0,0),
(10,8,693,12521,1000,1,0,0,1,1,0,1,0,0),
(10,8,694,8179,1000,1,0,0,1,1,0,1,0,0),
(10,8,695,9704,1000,1,0,0,1,1,0,1,0,0),
(10,8,696,15448,1000,1,0,0,1,1,0,1,0,0),
(10,8,697,11162,1000,1,0,0,1,1,0,1,0,0),
(10,8,698,11163,1000,1,0,0,1,1,0,1,0,0),
(10,8,699,11164,1000,1,0,0,1,1,0,1,0,0),
(10,8,700,11165,1000,1,0,0,1,1,0,1,0,0),
(10,8,701,11661,1000,1,0,0,1,1,0,1,0,0),
(10,8,702,11662,1000,1,0,0,1,1,0,1,0,0),
(10,8,703,14639,1000,1,0,0,1,1,0,1,0,0),
(10,8,704,13607,10,1,0,0,1,1,0,1,0,0),
(10,7,705,15774,3000,1,0,0,1,1,0,1,100,0),
(10,7,706,15775,3000,1,0,0,1,1,0,1,100,0),
(10,7,707,11420,3000,1,0,0,1,1,0,1,100,0),
(10,7,708,14704,3000,1,0,0,1,1,0,1,100,0),
(10,7,709,13177,3000,1,0,0,1,1,0,1,100,0),
(10,7,710,14191,3000,1,0,0,1,1,0,1,100,0),
(10,7,711,13449,3000,1,0,0,1,1,0,1,100,0),
(10,7,712,14192,3000,1,0,0,1,1,0,1,100,0),
(10,7,713,15772,3000,1,0,0,1,1,0,1,100,0),
(10,7,714,13791,3000,1,0,0,1,1,0,1,100,0),
(10,7,715,14006,3000,1,0,0,1,1,0,1,100,0),
(10,7,716,15768,3000,1,0,0,1,1,0,1,100,0),
(10,7,717,14069,3000,1,0,0,1,1,0,1,100,0),
(10,7,718,14124,3000,1,0,0,1,1,0,1,100,0),
(10,7,719,15507,3000,1,0,0,1,1,0,1,100,0),
(10,7,720,15508,3000,1,0,0,1,1,0,1,100,0),
(10,7,721,14855,3000,1,0,0,1,1,0,1,100,0),
(10,7,722,14894,3000,1,0,0,1,1,0,1,100,0),
(10,7,723,16444,3000,1,0,0,1,1,0,1,100,0),
(10,7,724,16445,3000,1,0,0,1,1,0,1,100,0),
(10,7,725,12509,3000,1,0,0,1,1,0,1,100,0),
(10,7,726,14126,3000,1,0,0,1,1,0,1,100,0),
(10,7,727,15062,3000,1,0,0,1,1,0,1,100,0),
(10,7,728,15063,3000,1,0,0,1,1,0,1,100,0),
(10,7,729,14891,3000,1,0,0,1,1,0,1,100,0),
(10,7,730,14895,3000,1,0,0,1,1,0,1,100,0),
(10,7,731,14091,3000,1,0,0,1,1,0,1,100,0),
(10,7,732,14092,3000,1,0,0,1,1,0,1,100,0),
(10,7,733,14501,3000,1,0,0,1,1,0,1,100,0),
(10,7,734,14506,3000,1,0,0,1,1,0,1,100,0),
(10,7,735,15285,3000,1,0,0,1,1,0,1,100,0),
(10,7,736,15286,3000,1,0,0,1,1,0,1,100,0),
(10,7,737,16442,3000,1,0,0,1,1,0,1,100,0),
(10,7,738,16443,3000,1,0,0,1,1,0,1,100,0),
(10,7,739,15027,3000,1,0,0,1,1,0,1,100,0),
(10,7,740,15028,3000,1,0,0,1,1,0,1,100,0),
(10,7,741,13453,3000,1,0,0,1,1,0,1,100,0),
(10,7,742,14193,3000,1,0,0,1,1,0,1,100,0),
(10,7,743,13178,3000,1,0,0,1,1,0,1,100,0),
(10,7,744,14194,3000,1,0,0,1,1,0,1,100,0),
(10,7,745,16454,3000,1,0,0,1,1,0,1,100,0),
(10,7,746,16455,3000,1,0,0,1,1,0,1,100,0),
(10,7,747,15030,3000,1,0,0,1,1,0,1,100,0),
(10,7,748,15031,3000,1,0,0,1,1,0,1,100,0),
(10,7,749,13790,3000,1,0,0,1,1,0,1,100,0),
(10,7,750,14005,3000,1,0,0,1,1,0,1,100,0),
(10,7,751,14406,3000,1,0,0,1,1,0,1,100,0),
(10,7,752,14413,3000,1,0,0,1,1,0,1,100,0),
(10,7,753,16448,3000,1,0,0,1,1,0,1,100,0),
(10,7,754,16449,3000,1,0,0,1,1,0,1,100,0),
(10,7,755,12872,3000,1,0,0,1,1,0,1,100,0),
(10,7,756,14187,3000,1,0,0,1,1,0,1,100,0),
(10,7,757,14125,3000,1,0,0,1,1,0,1,100,0),
(10,7,758,14500,3000,1,0,0,1,1,0,1,100,0),
(10,7,759,14505,3000,1,0,0,1,1,0,1,100,0),
(10,7,760,15118,3000,1,0,0,1,1,0,1,100,0),
(10,7,761,15119,3000,1,0,0,1,1,0,1,100,0),
(10,7,762,14662,3000,1,0,0,1,1,0,1,100,0),
(10,7,763,14663,3000,1,0,0,1,1,0,1,100,0),
(10,7,764,15771,3000,1,0,0,1,1,0,1,100,0),
(10,7,765,9700,3000,1,0,0,1,1,0,1,100,0),
(10,7,766,14498,3000,1,0,0,1,1,0,1,100,0),
(10,7,767,14913,3000,1,0,0,1,1,0,1,100,0),
(10,7,768,14914,3000,1,0,0,1,1,0,1,100,0),
(10,7,769,13508,3000,1,0,0,1,1,0,1,100,0),
(10,7,770,15115,3000,1,0,0,1,1,0,1,100,0),
(10,7,771,15116,3000,1,0,0,1,1,0,1,100,0),
(10,7,772,15113,3000,1,0,0,1,1,0,1,100,0),
(10,7,773,15114,3000,1,0,0,1,1,0,1,100,0),
(10,7,774,15222,3000,1,0,0,1,1,0,1,100,0),
(10,7,775,15223,3000,1,0,0,1,1,0,1,100,0),
(10,7,776,10750,3000,1,0,0,1,1,0,1,100,0),
(10,7,777,14705,3000,1,0,0,1,1,0,1,100,0),
(10,7,778,15027,3000,1,0,0,1,1,0,1,100,0),
(10,7,779,15028,3000,1,0,0,1,1,0,1,100,0),
(10,7,780,10380,3000,1,0,0,1,1,0,1,100,0),
(10,7,781,15060,3000,1,0,0,1,1,0,1,100,0),
(10,7,782,13963,3000,1,0,0,1,1,0,1,100,0),
(10,7,783,14026,3000,1,0,0,1,1,0,1,100,0),
(10,7,784,13964,3000,1,0,0,1,1,0,1,100,0),
(10,7,785,14027,3000,1,0,0,1,1,0,1,100,0),
(10,7,786,15064,3000,1,0,0,1,1,0,1,100,0),
(10,7,787,15065,3000,1,0,0,1,1,0,1,100,0),
(10,7,788,15524,3000,1,0,0,1,1,0,1,100,0),
(10,7,789,15525,3000,1,0,0,1,1,0,1,100,0),
(10,7,790,16450,3000,1,0,0,1,1,0,1,100,0),
(10,7,791,16451,3000,1,0,0,1,1,0,1,100,0),
(10,7,792,16344,3000,1,0,0,1,1,0,1,100,0),
(10,7,793,16345,3000,1,0,0,1,1,0,1,100,0),
(10,7,794,16342,3000,1,0,0,1,1,0,1,100,0),
(10,7,795,16343,3000,1,0,0,1,1,0,1,100,0),
(10,7,796,15220,3000,1,0,0,1,1,0,1,100,0),
(10,7,797,15221,3000,1,0,0,1,1,0,1,100,0),
(10,7,798,15066,3000,1,0,0,1,1,0,1,100,0),
(10,7,799,15067,3000,1,0,0,1,1,0,1,100,0),
(10,7,800,14089,3000,1,0,0,1,1,0,1,100,0),
(10,7,801,14090,3000,1,0,0,1,1,0,1,100,0),
(10,7,802,14195,3000,1,0,0,1,1,0,1,100,0),
(10,7,803,14196,3000,1,0,0,1,1,0,1,100,0),
(10,7,804,13965,3000,1,0,0,1,1,0,1,100,0),
(10,7,805,14028,3000,1,0,0,1,1,0,1,100,0),
(10,7,806,13508,3000,1,0,0,1,1,0,1,100,0),
(10,7,807,13962,3000,1,0,0,1,1,0,1,100,0),
(10,7,808,14314,3000,1,0,0,1,1,0,1,100,0),
(10,7,809,13404,3000,1,0,0,1,1,0,1,100,0),
(10,7,810,14188,3000,1,0,0,1,1,0,1,100,0),
(10,7,811,14032,3000,1,0,0,1,1,0,1,100,0),
(10,7,812,13960,3000,1,0,0,1,1,0,1,100,0),
(10,7,813,15819,3000,1,0,0,1,1,0,1,100,0),
(10,7,814,15820,3000,1,0,0,1,1,0,1,100,0),
(10,7,815,10750,3000,1,0,0,1,1,0,1,100,0),
(10,7,816,14705,3000,1,0,0,1,1,0,1,100,0),
(10,7,817,14407,3000,1,0,0,1,1,0,1,100,0),
(10,7,818,14414,3000,1,0,0,1,1,0,1,100,0),
(10,7,819,16352,3000,1,0,0,1,1,0,1,100,0),
(10,7,820,16353,3000,1,0,0,1,1,0,1,100,0),
(10,7,821,14502,3000,1,0,0,1,1,0,1,100,0),
(10,7,822,14507,3000,1,0,0,1,1,0,1,100,0),
(10,7,823,10811,3000,1,0,0,1,1,0,1,100,0),
(10,7,824,15061,3000,1,0,0,1,1,0,1,100,0),
(10,7,825,15823,3000,1,0,0,1,1,0,1,100,0),
(10,7,826,15824,3000,1,0,0,1,1,0,1,100,0),
(10,7,827,15224,3000,1,0,0,1,1,0,1,100,0),
(10,7,828,15225,3000,1,0,0,1,1,0,1,100,0),
(10,7,829,14503,3000,1,0,0,1,1,0,1,100,0),
(10,7,830,14510,3000,1,0,0,1,1,0,1,100,0),
(10,7,831,15776,3000,1,0,0,1,1,0,1,100,0),
(10,7,832,15777,3000,1,0,0,1,1,0,1,100,0),
(10,7,833,15821,3000,1,0,0,1,1,0,1,100,0),
(10,7,834,15822,3000,1,0,0,1,1,0,1,100,0),
(10,7,835,14198,3000,1,0,0,1,1,0,1,100,0),
(10,7,836,14197,3000,1,0,0,1,1,0,1,100,0),
(10,7,837,16446,3000,1,0,0,1,1,0,1,100,0),
(10,7,838,16447,3000,1,0,0,1,1,0,1,100,0),
(10,7,839,14905,3000,1,0,0,1,1,0,1,100,0),
(10,7,840,14907,3000,1,0,0,1,1,0,1,100,0),
(10,7,841,14904,3000,1,0,0,1,1,0,1,100,0),
(10,7,842,14906,3000,1,0,0,1,1,0,1,100,0),
(10,7,843,14659,3000,1,0,0,1,1,0,1,100,0),
(10,7,844,14660,3000,1,0,0,1,1,0,1,100,0),
(10,7,845,13326,3000,1,0,0,1,1,0,1,100,0),
(10,7,846,14416,3000,1,0,0,1,1,0,1,100,0),
(10,7,847,13450,3000,1,0,0,1,1,0,1,100,0),
(10,7,848,14031,3000,1,0,0,1,1,0,1,100,0),
(10,7,849,16492,3000,1,0,0,1,1,0,1,100,0),
(10,7,850,16493,3000,1,0,0,1,1,0,1,100,0),
(10,8,851,1520,1,1,0,0,1,1,0,1,0,0),
(10,8,852,7011,1,1,0,0,1,1,0,1,0,0),
(10,7,853,14299,500,1,0,0,1,1,0,1,20,0),
(10,7,854,14389,500,1,0,0,1,1,0,1,20,0),
(10,7,855,15177,500,1,0,0,1,1,0,1,20,0),
(10,7,856,14537,500,1,0,0,1,1,0,1,20,0),
(10,7,857,14758,500,1,0,0,1,1,0,1,20,0),
(10,7,858,14854,500,1,0,0,1,1,0,1,20,0),
(10,7,859,13974,500,1,0,0,1,1,0,1,20,0),
(10,7,860,15021,500,1,0,0,1,1,0,1,20,0),
(10,7,861,15111,500,1,0,0,1,1,0,1,20,0),
(10,7,862,15226,500,1,0,0,1,1,0,1,20,0),
(10,7,863,15773,500,1,0,0,1,1,0,1,20,0),
(10,7,864,15825,500,1,0,0,1,1,0,1,20,0),
(10,7,865,15827,500,1,0,0,1,1,0,1,20,0),
(10,7,866,16340,500,1,0,0,1,1,0,1,20,0),
(10,7,867,16341,500,1,0,0,1,1,0,1,20,0),
(10,7,868,16457,500,1,0,0,1,1,0,1,20,0),
(10,7,869,16458,500,1,0,0,1,1,0,1,20,0),
(10,7,870,11698,250,1,0,0,1,1,0,1,50,0),
(10,7,871,11700,250,1,0,0,1,1,0,1,50,0),
(10,8,872,4358,10,1,0,0,1,1,0,1,0,0),
(10,8,873,7981,1,1,0,0,1,1,0,1,0,0),
(10,8,874,7267,20,1,0,0,1,1,0,1,0,0),
(10,8,875,9958,20,1,0,0,1,1,0,1,0,999),
(10,8,876,1548,20,1,0,0,1,1,0,1,0,0),
(10,8,877,1613,20,1,0,0,1,1,0,1,0,0),
(10,8,878,1026,1,1,0,0,1,1,0,1,0,0),
(10,8,879,5380,1,1,0,0,1,1,0,1,0,0),
(10,8,880,11284,15,1,0,0,1,1,0,1,0,0),
(10,8,881,11285,15,1,0,0,1,1,0,1,0,0),
(10,8,882,11286,15,1,0,0,1,1,0,1,0,0),
(10,8,883,10356,500,1,0,0,1,1,0,1,0,0),
(10,8,884,12511,500,1,0,0,1,1,0,1,0,0),
(10,8,885,13238,500,1,0,0,1,1,0,1,0,0),
(10,8,886,1691,1,1,0,0,1,1,0,1,0,0),
(10,8,887,9708,1,1,0,0,1,1,0,1,0,0),
(10,8,888,11383,10,1,0,0,1,1,0,1,0,0),
(10,8,889,11382,10,1,0,0,1,1,0,1,0,0),
(10,8,890,11381,10,1,0,0,1,1,0,1,0,0),
(10,7,891,16348,3000,1,0,0,1,1,0,1,100,0),
(10,8,892,11386,10,1,0,0,1,1,0,1,0,0),
(10,8,893,5767,1,10000,0,0,1,1,0,1,0,0),
(10,8,894,5765,1,10000,0,0,1,1,0,1,0,0),
(10,8,895,5768,1,10000,0,0,1,1,0,1,0,0),
(10,8,896,14444,10,1,0,0,1,1,0,1,0,0),
(10,8,897,14443,10,1,0,0,1,1,0,1,0,0),
(10,8,898,14445,10,1,0,0,1,1,0,1,0,0),
(10,8,899,15068,500,1,0,0,1,1,0,1,20,0),
(10,7,900,16532,1000,1,0,0,1,1,0,1,0,0),
(10,8,901,100,1,10000,0,0,1,1,0,1,0,0),
(10,8,902,11243,1,1,0,0,1,1,0,1,0,0),
(10,8,903,101,1,10000,0,0,1,1,0,1,0,0),
(10,7,904,14368,3000,1,0,0,1,1,0,1,50,0),
(10,8,905,8943,1,20,0,0,1,1,0,1,0,0),
(10,7,906,1622,3000,1,0,0,1,1,0,1,0,0),
(10,8,907,8953,1,20,0,0,1,1,0,1,0,0),
(10,8,908,13693,1,20,0,0,1,1,0,1,0,0),
(10,8,909,8949,1,20,0,0,1,1,0,1,0,0),
(10,8,910,8955,1,20,0,0,1,1,0,1,0,0),
(10,7,911,16456,500,1,0,0,1,1,0,1,0,0);
END;

View File

@@ -2,14 +2,17 @@
"Host": "127.0.0.1",
"BinPath": "bin",
"DisableSoftCrash": false,
"devmode": true,
"devmodeoptions": {
"serverName" : "",
"FeaturedWeapons": 1,
"DevMode": true,
"DevModeOptions": {
"PatchServerManifest": "",
"PatchServerFile": "",
"AutoCreateAccount": true,
"EnableLauncherServer": false,
"hideLoginNotice": false,
"loginNotice": "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.1 Beta!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you.",
"cleandb": false,
"maxlauncherhr": false,
"HideLoginNotice": false,
"LoginNotice": "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.1 Beta!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you.",
"CleanDB": false,
"MaxLauncherHR": false,
"LogInboundMessages": false,
"LogOutboundMessages": false,
"MaxHexdumpLength": 256,
@@ -20,64 +23,108 @@
"MezFesAlt": false,
"DisableMailItems": true,
"DisableTokenCheck": false,
"QuestDebugTools": false,
"SaveDumps": {
"Enabled": true,
"OutputDir": "savedata"
}
},
"discord": {
"enabled": false,
"bottoken": "",
"realtimeChannelID": ""
"Discord": {
"Enabled": false,
"BotToken": "",
"RealtimeChannelID": ""
},
"database": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "",
"database": "erupe"
"Commands": [
{
"Name": "Rights",
"Enabled": false,
"Prefix": "!rights"
}, {
"Name": "Raviente",
"Enabled": true,
"Prefix": "!ravi"
}, {
"Name": "Teleport",
"Enabled": false,
"Prefix": "!tele"
}, {
"Name": "Reload",
"Enabled": true,
"Prefix": "!reload"
}, {
"Name": "KeyQuest",
"Enabled": false,
"Prefix": "!kqf"
}, {
"Name": "Course",
"Enabled": true,
"Prefix": "!course"
}
],
"Courses": [
{"Name": "HunterLife", "Enabled": true},
{"Name": "ExtraA", "Enabled": true},
{"Name": "Premium", "Enabled": true},
{"Name": "Assist", "Enabled": false},
{"Name": "Netcafe", "Enabled": false},
{"Name": "Hiden", "Enabled": false},
{"Name": "HunterSupport", "Enabled": false},
{"Name": "NetcafeBoost", "Enabled": false}
],
"Database": {
"Host": "localhost",
"Port": 5432,
"User": "postgres",
"Password": "",
"Database": "erupe"
},
"launcher": {
"port": 80,
"Launcher": {
"Enabled": false,
"Port": 80,
"UseOriginalLauncherFiles": false
},
"sign": {
"port": 53312
"Sign": {
"Enabled": true,
"Port": 53312
},
"entrance": {
"port": 53310,
"entries": [
"Channel": {
"Enabled": true
},
"Entrance": {
"Enabled": true,
"Port": 53310,
"Entries": [
{
"name": "Newbie", "description": "", "ip": "", "type": 3, "recommended": 2, "allowedclientflags": 0,
"channels": [
{ "port": 54001, "MaxPlayers": 100 },
{ "port": 54002, "MaxPlayers": 100 }
"Name": "Newbie", "Description": "", "IP": "", "Type": 3, "Recommended": 2, "AllowedClientFlags": 0,
"Channels": [
{ "Port": 54001, "MaxPlayers": 100 },
{ "Port": 54002, "MaxPlayers": 100 }
]
}, {
"name": "Normal", "description": "", "ip": "", "type": 1, "recommended": 0, "allowedclientflags": 0,
"channels": [
{ "port": 54003, "MaxPlayers": 100 },
{ "port": 54004, "MaxPlayers": 100 }
"Name": "Normal", "Description": "", "IP": "", "Type": 1, "Recommended": 0, "AllowedClientFlags": 0,
"Channels": [
{ "Port": 54003, "MaxPlayers": 100 },
{ "Port": 54004, "MaxPlayers": 100 }
]
}, {
"name": "Cities", "description": "", "ip": "", "type": 2, "recommended": 0, "allowedclientflags": 0,
"channels": [
{ "port": 54005, "MaxPlayers": 100 }
"Name": "Cities", "Description": "", "IP": "", "Type": 2, "Recommended": 0, "AllowedClientFlags": 0,
"Channels": [
{ "Port": 54005, "MaxPlayers": 100 }
]
}, {
"name": "Tavern", "description": "", "ip": "", "type": 4, "recommended": 0, "allowedclientflags": 0,
"channels": [
{ "port": 54006, "MaxPlayers": 100 }
"Name": "Tavern", "Description": "", "IP": "", "Type": 4, "Recommended": 0, "AllowedClientFlags": 0,
"Channels": [
{ "Port": 54006, "MaxPlayers": 100 }
]
}, {
"name": "Return", "description": "", "ip": "", "type": 5, "recommended": 0, "allowedclientflags": 0,
"channels": [
{ "port": 54007, "MaxPlayers": 100 }
"Name": "Return", "Description": "", "IP": "", "Type": 5, "Recommended": 0, "AllowedClientFlags": 0,
"Channels": [
{ "Port": 54007, "MaxPlayers": 100 }
]
}, {
"name": "MezFes", "description": "", "ip": "", "type": 6, "recommended": 6, "allowedclientflags": 0,
"channels": [
{ "port": 54008, "MaxPlayers": 100 }
"Name": "MezFes", "Description": "", "IP": "", "Type": 6, "Recommended": 6, "AllowedClientFlags": 0,
"Channels": [
{ "Port": 54008, "MaxPlayers": 100 }
]
}
]

View File

@@ -1,8 +1,11 @@
package config
import (
"fmt"
"log"
"net"
"os"
"time"
"github.com/spf13/viper"
)
@@ -12,36 +15,41 @@ type Config struct {
Host string `mapstructure:"Host"`
BinPath string `mapstructure:"BinPath"`
DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically
FeaturedWeapons int // Number of Active Feature weapons to generate daily
DevMode bool
DevModeOptions DevModeOptions
Discord Discord
Commands []Command
Courses []Course
Database Database
Launcher Launcher
Sign Sign
Channel Channel
Entrance Entrance
}
// DevModeOptions holds various debug/temporary options for use while developing Erupe.
type DevModeOptions struct {
ServerName string // To get specific instance server about (Current Players/Event Week)
EnableLauncherServer bool // Enables the launcher server to be served on port 80
HideLoginNotice bool // Hide the Erupe notice on login
LoginNotice string // MHFML string of the login notice displayed
CleanDB bool // Automatically wipes the DB on server reset.
MaxLauncherHR bool // Sets the HR returned in the launcher to HR9 so that you can join non-beginner worlds.
FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages
LogInboundMessages bool // Log all messages sent to the server
LogOutboundMessages bool // Log all messages sent to the clients
MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
DivaEvent int // Diva Defense event status
FestaEvent int // Hunter's Festa event status
TournamentEvent int // VS Tournament event status
MezFesEvent bool // MezFes status
MezFesAlt bool // Swaps out Volpakkun for Tokotoko
DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
DisableMailItems bool // Hack to prevent english versions of MHF from crashing
SaveDumps SaveDumpOptions
PatchServerManifest string // Manifest patch server override
PatchServerFile string // File patch server override
AutoCreateAccount bool // Automatically create accounts if they don't exist
HideLoginNotice bool // Hide the Erupe notice on login
LoginNotice string // MHFML string of the login notice displayed
CleanDB bool // Automatically wipes the DB on server reset.
MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds.
LogInboundMessages bool // Log all messages sent to the server
LogOutboundMessages bool // Log all messages sent to the clients
MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
DivaEvent int // Diva Defense event status
FestaEvent int // Hunter's Festa event status
TournamentEvent int // VS Tournament event status
MezFesEvent bool // MezFes status
MezFesAlt bool // Swaps out Volpakkun for Tokotoko
DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
DisableMailItems bool // Hack to prevent english versions of MHF from crashing
QuestDebugTools bool // Enable various quest debug logs
SaveDumps SaveDumpOptions
}
type SaveDumpOptions struct {
@@ -53,10 +61,20 @@ type SaveDumpOptions struct {
type Discord struct {
Enabled bool
BotToken string
ServerID string
RealtimeChannelID string
DevRoles []string
DevMode bool
}
// Command is a channelserver chat command
type Command struct {
Name string
Enabled bool
Prefix string
}
// Course represents a course within MHF
type Course struct {
Name string
Enabled bool
}
// Database holds the postgres database config.
@@ -70,17 +88,24 @@ type Database struct {
// Launcher holds the launcher server config.
type Launcher struct {
Enabled bool
Port int
UseOriginalLauncherFiles bool
}
// Sign holds the sign server config.
type Sign struct {
Port int
Enabled bool
Port int
}
type Channel struct {
Enabled bool
}
// Entrance holds the entrance server config.
type Entrance struct {
Enabled bool
Port uint16
Entries []EntranceServerInfo
}
@@ -107,6 +132,17 @@ type EntranceChannelInfo struct {
CurrentPlayers uint16
}
var ErupeConfig *Config
func init() {
var err error
ErupeConfig, err = LoadConfig()
if err != nil {
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
}
}
// getOutboundIP4 gets the preferred outbound ip4 of this machine
// From https://stackoverflow.com/a/37382208
func getOutboundIP4() net.IP {
@@ -148,3 +184,20 @@ func LoadConfig() (*Config, error) {
return c, nil
}
func preventClose(text string) {
if ErupeConfig.DisableSoftCrash {
os.Exit(0)
}
fmt.Println("\nFailed to start Erupe:\n" + text)
go wait()
fmt.Println("\nPress Enter/Return to exit...")
fmt.Scanln()
os.Exit(0)
}
func wait() {
for {
time.Sleep(time.Millisecond * 100)
}
}

33
go.mod
View File

@@ -1,23 +1,38 @@
module erupe-ce
go 1.16
go 1.19
require (
github.com/bwmarrin/discordgo v0.23.2
github.com/golang/mock v1.6.0 // indirect
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2 // indirect
github.com/jmoiron/sqlx v1.3.4
github.com/lib/pq v1.10.4
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96
github.com/spf13/viper v1.8.1
go.uber.org/zap v1.18.1
golang.org/x/crypto v0.1.0
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
golang.org/x/text v0.4.0
)
require (
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/pelletier/go-toml v1.9.3 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.18.1
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.8 // indirect
golang.org/x/sys v0.1.0 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

40
go.sum
View File

@@ -78,9 +78,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -189,9 +188,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -202,9 +200,8 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -222,9 +219,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -265,7 +261,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
@@ -295,8 +290,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -307,6 +302,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc=
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -333,7 +330,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -370,8 +366,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -435,12 +429,9 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -449,9 +440,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -508,8 +498,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -617,9 +606,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

189
main.go
View File

@@ -14,13 +14,12 @@ import (
"erupe-ce/server/entranceserver"
"erupe-ce/server/launcherserver"
"erupe-ce/server/signserver"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
var erupeConfig *config.Config
// Temporary DB auto clean on startup for quick development & testing.
func cleanDB(db *sqlx.DB) {
_ = db.MustExec("DELETE FROM guild_characters")
@@ -36,27 +35,21 @@ func main() {
defer zapLogger.Sync()
logger := zapLogger.Named("main")
logger.Info("Starting Erupe")
logger.Info("Starting Erupe (9.1b)")
// Load the configuration.
erupeConfig, err = config.LoadConfig()
if err != nil {
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
}
if erupeConfig.Database.Password == "" {
if config.ErupeConfig.Database.Password == "" {
preventClose("Database password is blank")
}
if net.ParseIP(erupeConfig.Host) == nil {
ips, _ := net.LookupIP(erupeConfig.Host)
if net.ParseIP(config.ErupeConfig.Host) == nil {
ips, _ := net.LookupIP(config.ErupeConfig.Host)
for _, ip := range ips {
if ip != nil {
erupeConfig.Host = ip.String()
config.ErupeConfig.Host = ip.String()
break
}
}
if net.ParseIP(erupeConfig.Host) == nil {
if net.ParseIP(config.ErupeConfig.Host) == nil {
preventClose("Invalid host address")
}
}
@@ -64,10 +57,10 @@ func main() {
// Discord bot
var discordBot *discordbot.DiscordBot = nil
if erupeConfig.Discord.Enabled {
if config.ErupeConfig.Discord.Enabled {
bot, err := discordbot.NewDiscordBot(discordbot.Options{
Logger: logger,
Config: erupeConfig,
Config: config.ErupeConfig,
})
if err != nil {
@@ -90,11 +83,11 @@ func main() {
// Create the postgres DB pool.
connectString := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname= %s sslmode=disable",
erupeConfig.Database.Host,
erupeConfig.Database.Port,
erupeConfig.Database.User,
erupeConfig.Database.Password,
erupeConfig.Database.Database,
config.ErupeConfig.Database.Host,
config.ErupeConfig.Database.Port,
config.ErupeConfig.Database.User,
config.ErupeConfig.Database.Password,
config.ErupeConfig.Database.Database,
)
db, err := sqlx.Open("postgres", connectString)
@@ -112,11 +105,9 @@ func main() {
// Clear stale data
_ = db.MustExec("DELETE FROM sign_sessions")
_ = db.MustExec("DELETE FROM servers")
_ = db.MustExec("DELETE FROM cafe_accepted")
_ = db.MustExec("UPDATE characters SET cafe_time=0")
// Clean the DB if the option is on.
if erupeConfig.DevMode && erupeConfig.DevModeOptions.CleanDB {
if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB {
logger.Info("Cleaning DB")
cleanDB(db)
logger.Info("Done cleaning DB")
@@ -126,13 +117,13 @@ func main() {
// Launcher HTTP server.
var launcherServer *launcherserver.Server
if erupeConfig.DevMode && erupeConfig.DevModeOptions.EnableLauncherServer {
if config.ErupeConfig.Launcher.Enabled {
launcherServer = launcherserver.NewServer(
&launcherserver.Config{
Logger: logger.Named("launcher"),
ErupeConfig: erupeConfig,
ErupeConfig: config.ErupeConfig,
DB: db,
UseOriginalLauncherFiles: erupeConfig.Launcher.UseOriginalLauncherFiles,
UseOriginalLauncherFiles: config.ErupeConfig.Launcher.UseOriginalLauncherFiles,
})
err = launcherServer.Start()
if err != nil {
@@ -142,72 +133,83 @@ func main() {
}
// Entrance server.
entranceServer := entranceserver.NewServer(
&entranceserver.Config{
Logger: logger.Named("entrance"),
ErupeConfig: erupeConfig,
DB: db,
})
err = entranceServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error()))
var entranceServer *entranceserver.Server
if config.ErupeConfig.Entrance.Enabled {
entranceServer = entranceserver.NewServer(
&entranceserver.Config{
Logger: logger.Named("entrance"),
ErupeConfig: config.ErupeConfig,
DB: db,
})
err = entranceServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error()))
}
logger.Info("Started entrance server")
}
logger.Info("Started entrance server")
// Sign server.
signServer := signserver.NewServer(
&signserver.Config{
Logger: logger.Named("sign"),
ErupeConfig: erupeConfig,
DB: db,
})
err = signServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error()))
var signServer *signserver.Server
if config.ErupeConfig.Sign.Enabled {
signServer = signserver.NewServer(
&signserver.Config{
Logger: logger.Named("sign"),
ErupeConfig: config.ErupeConfig,
DB: db,
})
err = signServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error()))
}
logger.Info("Started sign server")
}
logger.Info("Started sign server")
var channels []*channelserver.Server
channelQuery := ""
si := 0
ci := 0
count := 1
for _, ee := range erupeConfig.Entrance.Entries {
for _, ce := range ee.Channels {
sid := (4096 + si*256) + (16 + ci)
c := *channelserver.NewServer(&channelserver.Config{
ID: uint16(sid),
Logger: logger.Named("channel-" + fmt.Sprint(count)),
ErupeConfig: erupeConfig,
DB: db,
DiscordBot: discordBot,
})
if ee.IP == "" {
c.IP = erupeConfig.Host
} else {
c.IP = ee.IP
}
c.Port = ce.Port
err = c.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error()))
} else {
channelQuery += fmt.Sprintf("INSERT INTO servers (server_id, season, current_players) VALUES (%d, %d, 0);", sid, si%3)
channels = append(channels, &c)
logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port))
ci++
count++
if config.ErupeConfig.Channel.Enabled {
channelQuery := ""
si := 0
ci := 0
count := 1
for _, ee := range config.ErupeConfig.Entrance.Entries {
for i, ce := range ee.Channels {
sid := (4096 + si*256) + (16 + ci)
c := *channelserver.NewServer(&channelserver.Config{
ID: uint16(sid),
Logger: logger.Named("channel-" + fmt.Sprint(count)),
ErupeConfig: config.ErupeConfig,
DB: db,
DiscordBot: discordBot,
})
if ee.IP == "" {
c.IP = config.ErupeConfig.Host
} else {
c.IP = ee.IP
}
c.Port = ce.Port
err = c.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error()))
} else {
channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, season, current_players, world_name, world_description, land) VALUES (%d, %d, 0, '%s', '%s', %d);`, sid, si%3, ee.Name, ee.Description, i+1)
channels = append(channels, &c)
logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port))
ci++
count++
}
}
ci = 0
si++
}
ci = 0
si++
}
// Register all servers in DB
_ = db.MustExec(channelQuery)
// Register all servers in DB
_ = db.MustExec(channelQuery)
for _, c := range channels {
c.Channels = channels
for _, c := range channels {
c.Channels = channels
}
}
// Wait for exit or interrupt with ctrl+C.
@@ -217,12 +219,21 @@ func main() {
logger.Info("Trying to shutdown gracefully")
for _, c := range channels {
c.Shutdown()
if config.ErupeConfig.Channel.Enabled {
for _, c := range channels {
c.Shutdown()
}
}
signServer.Shutdown()
entranceServer.Shutdown()
if erupeConfig.DevModeOptions.EnableLauncherServer {
if config.ErupeConfig.Sign.Enabled {
signServer.Shutdown()
}
if config.ErupeConfig.Entrance.Enabled {
entranceServer.Shutdown()
}
if config.ErupeConfig.Launcher.Enabled {
launcherServer.Shutdown()
}
@@ -236,7 +247,7 @@ func wait() {
}
func preventClose(text string) {
if erupeConfig.DisableSoftCrash {
if config.ErupeConfig.DisableSoftCrash {
os.Exit(0)
}
fmt.Println("\nFailed to start Erupe:\n" + text)

View File

@@ -1,10 +0,0 @@
BEGIN;
DROP TABLE IF EXISTS sign_sessions;
DROP TABLE IF EXISTS characters;
DROP TABLE IF EXISTS users;
DROP DOMAIN IF EXISTS uint8;
DROP DOMAIN IF EXISTS uint16;
END;

View File

@@ -1,37 +0,0 @@
BEGIN;
CREATE DOMAIN uint8 AS smallint
CHECK(VALUE >= 0 AND VALUE <= 255);
CREATE DOMAIN uint16 AS integer
CHECK(VALUE >= 0 AND VALUE <= 65536);
CREATE TABLE users (
id serial NOT NULL PRIMARY KEY,
username text UNIQUE NOT NULL,
password text NOT NULL,
item_box bytea
);
CREATE TABLE characters (
id serial NOT NULL PRIMARY KEY,
user_id bigint REFERENCES users(id),
is_female boolean,
is_new_character boolean,
small_gr_level uint8,
gr_override_mode boolean,
name varchar(15),
unk_desc_string varchar(31),
gr_override_level uint16,
gr_override_unk0 uint8,
gr_override_unk1 uint8
);
CREATE TABLE sign_sessions (
id serial NOT NULL PRIMARY KEY,
user_id bigint REFERENCES users(id),
auth_token_num bigint,
auth_token_str text
);
END;

View File

@@ -1,8 +0,0 @@
BEGIN;
ALTER TABLE characters
DROP COLUMN exp,
DROP COLUMN weapon,
DROP COLUMN last_login;
END;

View File

@@ -1,8 +0,0 @@
BEGIN;
ALTER TABLE characters
ADD COLUMN exp uint16,
ADD COLUMN weapon uint16,
ADD COLUMN last_login integer;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE characters
DROP COLUMN savedata;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE characters
ADD COLUMN savedata bytea;
END;

View File

@@ -1,13 +0,0 @@
BEGIN;
ALTER TABLE characters
DROP COLUMN decomyset,
DROP COLUMN hunternavi,
DROP COLUMN otomoairou,
DROP COLUMN partner,
DROP COLUMN platebox,
DROP COLUMN platedata,
DROP COLUMN platemyset,
DROP COLUMN rengokudata;
END;

View File

@@ -1,14 +0,0 @@
BEGIN;
ALTER TABLE characters
ADD COLUMN decomyset bytea,
ADD COLUMN hunternavi bytea,
ADD COLUMN otomoairou bytea,
ADD COLUMN partner bytea,
ADD COLUMN platebox bytea,
ADD COLUMN platedata bytea,
ADD COLUMN platemyset bytea,
ADD COLUMN trophy bytea,
ADD COLUMN rengokudata bytea;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
DROP TABLE IF EXISTS questlists;
END;

View File

@@ -1,8 +0,0 @@
BEGIN;
CREATE TABLE questlists (
ind int NOT NULL PRIMARY KEY,
questlist bytea
);
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE characters
DROP COLUMN savemercenary;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE characters
ADD COLUMN savemercenary bytea;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
DROP TABLE guild_characters;
DROP TABLE guilds;
END;

View File

@@ -1,22 +0,0 @@
BEGIN;
CREATE TABLE guilds
(
id serial NOT NULL PRIMARY KEY,
name varchar(24),
created_at timestamp DEFAULT NOW(),
leader_id int NOT NULL,
main_motto varchar(255) DEFAULT ''
);
CREATE TABLE guild_characters
(
id serial NOT NULL PRIMARY KEY,
guild_id bigint REFERENCES guilds (id),
character_id bigint REFERENCES characters (id),
joined_at timestamp DEFAULT NOW()
);
CREATE UNIQUE INDEX guild_character_unique_index ON guild_characters (character_id);
END;

View File

@@ -1,11 +0,0 @@
BEGIN;
ALTER TABLE guilds
DROP COLUMN rp;
ALTER TABLE guild_characters
DROP COLUMN is_applicant,
DROP COLUMN is_sub_leader,
DROP COLUMN order_index;
END;

View File

@@ -1,11 +0,0 @@
BEGIN;
ALTER TABLE guild_characters
ADD COLUMN is_applicant bool NOT NULL DEFAULT false,
ADD COLUMN is_sub_leader bool NOT NULL DEFAULT false,
ADD COLUMN order_index int NOT NULL DEFAULT 1;
ALTER TABLE guilds
ADD COLUMN rp uint16 NOT NULL DEFAULT 0;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE characters
DROP COLUMN restrict_guild_scout;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE characters
ADD COLUMN restrict_guild_scout bool NOT NULL DEFAULT false;
END;

View File

@@ -1,10 +0,0 @@
BEGIN;
ALTER TABLE guilds
DROP COLUMN comment,
DROP COLUMN festival_colour,
DROP COLUMN guild_hall;
DROP TYPE festival_colour;
END;

View File

@@ -1,11 +0,0 @@
BEGIN;
CREATE TYPE festival_colour AS ENUM ('none', 'red', 'blue');
ALTER TABLE guilds
ADD COLUMN comment varchar(255) NOT NULL DEFAULT '',
ADD COLUMN festival_colour festival_colour DEFAULT 'none',
ADD COLUMN guild_hall int DEFAULT 0;
END;

View File

@@ -1,24 +0,0 @@
BEGIN;
ALTER TABLE characters
DROP COLUMN minidata,
DROP COLUMN gacha_trial,
DROP COLUMN gacha_prem,
DROP COLUMN gacha_items,
DROP COLUMN daily_time,
DROP COLUMN frontier_points,
DROP COLUMN netcafe_points,
DROP COLUMN house_info,
DROP COLUMN login_boost,
DROP COLUMN skin_hist,
DROP COLUMN gcp;
DROP TABLE fpoint_items;
DROP TABLE gacha_shop;
DROP TABLE gacha_shop_items;
DROP TABLE lucky_box_state;
DROP TABLE stepup_state;
DROP TABLE normal_shop_items;
DROP TABLE shop_item_state;
END;

View File

@@ -1,100 +0,0 @@
BEGIN;
ALTER TABLE characters
ADD COLUMN minidata bytea,
ADD COLUMN gacha_trial int,
ADD COLUMN gacha_prem int,
ADD COLUMN gacha_items bytea,
ADD COLUMN daily_time timestamp,
ADD COLUMN frontier_points int,
ADD COLUMN netcafe_points int,
ADD COLUMN house_info bytea,
ADD COLUMN login_boost bytea,
ADD COLUMN skin_hist bytea,
ADD COLUMN kouryou_point int,
ADD COLUMN gcp int;
CREATE TABLE fpoint_items
(
hash int,
itemType uint8,
itemID uint16,
quant uint16,
itemValue uint16,
tradeType uint8
);
CREATE TABLE gacha_shop
(
hash bigint,
reqGR int,
reqHR int,
gachaName varchar(255),
gachaLink0 varchar(255),
gachaLink1 varchar(255),
gachaLink2 varchar(255),
extraIcon int,
gachaType int,
hideFlag bool
);
CREATE TABLE gacha_shop_items
(
shophash int,
entryType uint8,
itemhash int UNIQUE NOT NULL,
currType uint8,
currNumber uint16,
currQuant uint16,
percentage uint16,
rarityIcon uint8,
rollsCount uint8,
itemCount uint8,
dailyLimit uint8,
itemType int[],
itemId int[],
quantity int[]
);
CREATE TABLE lucky_box_state
(
char_id bigint REFERENCES characters (id),
shophash int UNIQUE NOT NULL,
used_itemhash int[]
);
CREATE TABLE stepup_state
(
char_id bigint REFERENCES characters (id),
shophash int UNIQUE NOT NULL,
step_progression int,
step_time timestamp
);
CREATE TABLE normal_shop_items
(
shoptype int,
shopid int,
itemhash int UNIQUE NOT NULL,
itemID uint16,
Points uint16,
TradeQuantity uint16,
rankReqLow uint16,
rankReqHigh uint16,
rankReqG uint16,
storeLevelReq uint16,
maximumQuantity uint16,
boughtQuantity uint16,
roadFloorsRequired uint16,
weeklyFatalisKills uint16
);
CREATE TABLE shop_item_state
(
char_id bigint REFERENCES characters (id),
itemhash int UNIQUE NOT NULL,
usedquantity int
);
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
DROP TABLE login_boost_state;
END;

View File

@@ -1,13 +0,0 @@
BEGIN;
CREATE TABLE login_boost_state
(
char_id bigint REFERENCES characters (id),
week_req uint8,
week_count uint8,
available bool,
end_time int,
CONSTRAINT id_week UNIQUE(char_id, week_req)
);
END;

View File

@@ -1,12 +0,0 @@
BEGIN;
ALTER TABLE shop_item_state DROP CONSTRAINT shop_item_state_id_itemhash;
ALTER TABLE shop_item_state ADD CONSTRAINT shop_item_state_itemhash_key UNIQUE (itemhash);
ALTER TABLE stepup_state DROP CONSTRAINT stepup_state_id_shophash;
ALTER TABLE stepup_state ADD CONSTRAINT stepup_state_shophash_key UNIQUE (shophash);
ALTER TABLE lucky_box_state DROP CONSTRAINT lucky_box_state_id_shophash;
ALTER TABLE lucky_box_state ADD CONSTRAINT lucky_box_state_shophash_key UNIQUE (shophash);
END;

View File

@@ -1,12 +0,0 @@
BEGIN;
ALTER TABLE shop_item_state DROP CONSTRAINT shop_item_state_itemhash_key;
ALTER TABLE shop_item_state ADD CONSTRAINT shop_item_state_id_itemhash UNIQUE(char_id, itemhash);
ALTER TABLE stepup_state DROP CONSTRAINT stepup_state_shophash_key;
ALTER TABLE stepup_state ADD CONSTRAINT stepup_state_id_shophash UNIQUE(char_id, shophash);
ALTER TABLE lucky_box_state DROP CONSTRAINT lucky_box_state_shophash_key;
ALTER TABLE lucky_box_state ADD CONSTRAINT lucky_box_state_id_shophash UNIQUE(char_id, shophash);
END;

View File

@@ -1,18 +0,0 @@
BEGIN;
ALTER TABLE guild_characters
RENAME COLUMN avoid_leadership TO is_sub_leader;
ALTER TABLE guild_characters
ADD COLUMN is_applicant bool NOT NULL DEFAULT false;
ALTER TABLE guilds
DROP COLUMN icon,
ALTER COLUMN main_motto TYPE varchar USING '',
DROP COLUMN sub_motto;
ALTER TABLE guilds
ALTER COLUMN main_motto SET DEFAULT '';
DROP TABLE guild_applications;
DROP TYPE guild_application_type;
END;

View File

@@ -1,30 +0,0 @@
BEGIN;
CREATE TYPE guild_application_type AS ENUM ('applied', 'invited');
CREATE TABLE guild_applications
(
id serial NOT NULL PRIMARY KEY,
guild_id int NOT NULL REFERENCES guilds (id),
character_id int NOT NULL REFERENCES characters (id),
actor_id int NOT NULL REFERENCES characters (id),
application_type guild_application_type NOT NULL,
created_at timestamp NOT NULL DEFAULT now(),
CONSTRAINT guild_application_character_id UNIQUE (guild_id, character_id)
);
CREATE INDEX guild_application_type_index ON guild_applications (application_type);
ALTER TABLE guild_characters
DROP COLUMN is_applicant;
ALTER TABLE guild_characters
RENAME COLUMN is_sub_leader TO avoid_leadership;
ALTER TABLE guilds
ALTER COLUMN main_motto SET DEFAULT 0;
ALTER TABLE guilds
ADD COLUMN icon bytea,
ADD COLUMN sub_motto int DEFAULT 0,
ALTER COLUMN main_motto TYPE int USING 0;
END;

View File

@@ -1,3 +0,0 @@
BEGIN;
DROP TABLE mail;
END;

View File

@@ -1,19 +0,0 @@
BEGIN;
CREATE TABLE mail
(
id SERIAL NOT NULL PRIMARY KEY,
sender_id INT NOT NULL REFERENCES characters (id),
recipient_id INT NOT NULL REFERENCES characters (id),
subject VARCHAR NOT NULL DEFAULT '',
body VARCHAR NOT NULL DEFAULT '',
read BOOL NOT NULL DEFAULT FALSE,
attached_item_received BOOL NOT NULL DEFAULT FALSE,
attached_item INT DEFAULT NULL,
attached_item_amount INT NOT NULL DEFAULT 1,
is_guild_invite BOOL NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted BOOL NOT NULL DEFAULT FALSE
);
CREATE INDEX mail_recipient_deleted_created_id_index ON mail (recipient_id, deleted, created_at DESC, id DESC);
END;

View File

@@ -1,3 +0,0 @@
BEGIN;
DROP TABLE public.servers;
END;

View File

@@ -1,21 +0,0 @@
BEGIN;
-- Table: public.servers
-- DROP TABLE IF EXISTS public.servers;
CREATE TABLE IF NOT EXISTS public.servers
(
server_id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
server_name text COLLATE pg_catalog."default",
season integer,
current_players integer,
event_id integer,
event_expiration integer,
CONSTRAINT servers_pkey PRIMARY KEY (server_id)
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.servers
OWNER to postgres;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
DROP TABLE public.account_ban;
DROP TABLE public.account_history;
DROP TABLE public.account_moderation;
DROP TABLE public.account_sub;
END;

View File

@@ -1,45 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.account_ban
(
user_id integer NOT NULL,
title text COLLATE pg_catalog."default",
reason text COLLATE pg_catalog."default",
date text COLLATE pg_catalog."default",
pass_origin text COLLATE pg_catalog."default",
pass_block text COLLATE pg_catalog."default",
CONSTRAINT ban_pkey PRIMARY KEY (user_id)
);
CREATE TABLE IF NOT EXISTS public.account_history
(
report_id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
user_id integer,
title text COLLATE pg_catalog."default",
reason text COLLATE pg_catalog."default",
date date,
CONSTRAINT account_history_pkey PRIMARY KEY (report_id)
);
CREATE TABLE IF NOT EXISTS public.account_moderation
(
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
username text COLLATE pg_catalog."default",
password text COLLATE pg_catalog."default",
type text COLLATE pg_catalog."default",
CONSTRAINT account_moderation_pkey PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS public.account_sub
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
discord_id text COLLATE pg_catalog."default",
erupe_account text COLLATE pg_catalog."default",
erupe_password text COLLATE pg_catalog."default",
date_inscription date,
country text COLLATE pg_catalog."default",
presentation text COLLATE pg_catalog."default",
CONSTRAINT account_auth_pkey PRIMARY KEY (id)
);
END;

View File

@@ -1,3 +0,0 @@
BEGIN;
DROP TABLE public.event_week;
END;

View File

@@ -1,11 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.event_week
(
id integer NOT NULL,
event_id integer NOT NULL,
date_expiration integer NOT NULL,
CONSTRAINT event_week_pkey PRIMARY KEY (id)
);
END;

View File

@@ -1,3 +0,0 @@
BEGIN;
DROP TABLE public.gook;
END;

View File

@@ -1,20 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.gook
(
id serial NOT NULL PRIMARY KEY,
gook0 bytea,
gook1 bytea,
gook2 bytea,
gook3 bytea,
gook4 bytea,
gook5 bytea,
gook0status boolean,
gook1status boolean,
gook2status boolean,
gook3status boolean,
gook4status boolean,
gook5status boolean
);
END;

View File

@@ -1,3 +0,0 @@
BEGIN;
DROP TABLE public.history;
END;

View File

@@ -1,13 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.history
(
user_id integer,
admin_id integer,
report_id integer NOT NULL,
title text COLLATE pg_catalog."default",
reason text COLLATE pg_catalog."default",
CONSTRAINT history_pkey PRIMARY KEY (report_id)
);
END;

View File

@@ -1,8 +1,4 @@
package clientctx
import "erupe-ce/common/stringsupport"
// ClientContext holds contextual data required for packet encoding/decoding.
type ClientContext struct {
StrConv *stringsupport.StringConverter
}
type ClientContext struct{} // Unused

View File

@@ -32,6 +32,7 @@ type MsgMhfEnumerateGuild struct {
AckHandle uint32
Type EnumerateGuildType
Page uint8
Sorting bool
RawDataPayload []byte
}
@@ -45,6 +46,8 @@ func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
m.AckHandle = bf.ReadUint32()
m.Type = EnumerateGuildType(bf.ReadUint8())
m.Page = bf.ReadUint8()
m.Sorting = bf.ReadBool()
_ = bf.ReadUint8()
m.RawDataPayload = bf.DataFromCurrent()
bf.Seek(-2, io.SeekEnd)
return nil

View File

@@ -29,8 +29,10 @@ func (m *MsgMhfEnumerateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
m.CharID = bf.ReadUint32()
m.Method = bf.ReadUint8()
m.Unk = bf.ReadUint16()
_ = bf.ReadUint8() // len
m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
lenName := bf.ReadUint8()
if lenName > 0 {
m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
}
return nil
}

View File

@@ -1,15 +1,19 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgMhfGetGemInfo represents the MSG_MHF_GET_GEM_INFO
type MsgMhfGetGemInfo struct{}
type MsgMhfGetGemInfo struct {
AckHandle uint32
Unk uint32
Unk1 []byte
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfGetGemInfo) Opcode() network.PacketID {
@@ -18,7 +22,10 @@ func (m *MsgMhfGetGemInfo) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfGetGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
m.AckHandle = bf.ReadUint32()
m.Unk = bf.ReadUint32()
m.Unk1 = bf.ReadBytes(24)
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,11 +1,11 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// The server sends different responses based on these values.
@@ -13,7 +13,7 @@ const (
TowerInfoTypeUnk0 = iota
TowerInfoTypeTowerRankPoint
TowerInfoTypeGetOwnTowerSkill
TowerInfoTypeUnk3
TowerInfoTypeGetOwnTowerLevelV3
TowerInfoTypeTowerTouhaHistory
TowerInfoTypeUnk5
)

View File

@@ -1,17 +1,18 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgMhfGuildHuntdata represents the MSG_MHF_GUILD_HUNTDATA
type MsgMhfGuildHuntdata struct{
AckHandle uint32
Unk0 uint8
type MsgMhfGuildHuntdata struct {
AckHandle uint32
Operation uint8
GuildID uint32
}
// Opcode returns the ID associated with this packet type.
@@ -22,7 +23,10 @@ func (m *MsgMhfGuildHuntdata) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfGuildHuntdata) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
m.Operation = bf.ReadUint8()
if m.Operation == 1 {
m.GuildID = bf.ReadUint32()
}
return nil
}

View File

@@ -1,15 +1,19 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgMhfInfoJoint represents the MSG_MHF_INFO_JOINT
type MsgMhfInfoJoint struct{}
type MsgMhfInfoJoint struct {
AckHandle uint32
AllianceID uint32
Unk uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfInfoJoint) Opcode() network.PacketID {
@@ -18,7 +22,10 @@ func (m *MsgMhfInfoJoint) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfInfoJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
m.AckHandle = bf.ReadUint32()
m.AllianceID = bf.ReadUint32()
m.Unk = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,39 +1,43 @@
package mhfpacket
import (
"errors"
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
type OperateGuildAction uint8
const (
OPERATE_GUILD_DISBAND = 0x01
OPERATE_GUILD_APPLY = 0x02
OPERATE_GUILD_LEAVE = 0x03
OPERATE_GUILD_RESIGN = 0x04
OPERATE_GUILD_SET_APPLICATION_DENY = 0x05
OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06
OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07
OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08
OPERATE_GUILD_UPDATE_COMMENT = 0x09
OPERATE_GUILD_DONATE_RANK = 0x0a
OPERATE_GUILD_UPDATE_MOTTO = 0x0b
OPERATE_GUILD_RENAME_PUGI_1 = 0x0c
OPERATE_GUILD_RENAME_PUGI_2 = 0x0d
OPERATE_GUILD_RENAME_PUGI_3 = 0x0e
OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f
OPERATE_GUILD_CHANGE_PUGI_2 = 0x10
OPERATE_GUILD_CHANGE_PUGI_3 = 0x11
// pugi something
OPERATE_GUILD_DONATE_EVENT = 0x15
// pugi something
OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19
OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a
OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b
OPERATE_GUILD_DISBAND = 0x01
OPERATE_GUILD_APPLY = 0x02
OPERATE_GUILD_LEAVE = 0x03
OPERATE_GUILD_RESIGN = 0x04
OPERATE_GUILD_SET_APPLICATION_DENY = 0x05
OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06
OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07
OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08
OPERATE_GUILD_UPDATE_COMMENT = 0x09
OPERATE_GUILD_DONATE_RANK = 0x0a
OPERATE_GUILD_UPDATE_MOTTO = 0x0b
OPERATE_GUILD_RENAME_PUGI_1 = 0x0c
OPERATE_GUILD_RENAME_PUGI_2 = 0x0d
OPERATE_GUILD_RENAME_PUGI_3 = 0x0e
OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f
OPERATE_GUILD_CHANGE_PUGI_2 = 0x10
OPERATE_GUILD_CHANGE_PUGI_3 = 0x11
OPERATE_GUILD_UNLOCK_OUTFIT = 0x12
// 0x13 Unk
// 0x14 Unk
OPERATE_GUILD_DONATE_EVENT = 0x15
OPERATE_GUILD_EVENT_EXCHANGE = 0x16
// 0x17 Unk
// 0x18 Unk
OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19
OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a
OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b
)
// MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD
@@ -41,7 +45,8 @@ type MsgMhfOperateGuild struct {
AckHandle uint32
GuildID uint32
Action OperateGuildAction
UnkData []byte
Data1 *byteframe.ByteFrame
Data2 *byteframe.ByteFrame
}
// Opcode returns the ID associated with this packet type.
@@ -54,8 +59,9 @@ func (m *MsgMhfOperateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien
m.AckHandle = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
m.Action = OperateGuildAction(bf.ReadUint8())
m.UnkData = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
dataLen := uint(bf.ReadUint8())
m.Data1 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(4))
m.Data2 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(dataLen))
return nil
}

View File

@@ -1,28 +1,28 @@
package mhfpacket
import (
"errors"
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
type OperateJointAction uint8
const (
OPERATE_JOINT_DISBAND = 0x01
OPERATE_JOINT_LEAVE = 0x03
OPERATE_JOINT_KICK = 0x09
OPERATE_JOINT_DISBAND = 0x01
OPERATE_JOINT_LEAVE = 0x03
OPERATE_JOINT_KICK = 0x09
)
// MsgMhfOperateJoint represents the MSG_MHF_OPERATE_JOINT
type MsgMhfOperateJoint struct {
AckHandle uint32
AllianceID uint32
GuildID uint32
Action OperateJointAction
UnkData []byte
AckHandle uint32
AllianceID uint32
GuildID uint32
Action OperateJointAction
UnkData *byteframe.ByteFrame
}
// Opcode returns the ID associated with this packet type.
@@ -32,13 +32,13 @@ func (m *MsgMhfOperateJoint) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfOperateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.AllianceID = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
m.Action = OperateJointAction(bf.ReadUint8())
m.UnkData = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
return nil
m.AckHandle = bf.ReadUint32()
m.AllianceID = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
m.Action = OperateJointAction(bf.ReadUint8())
m.UnkData = byteframe.NewByteFrameFromBytes(bf.DataFromCurrent())
bf.Seek(int64(len(bf.Data())-2), 0)
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,17 +1,19 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// TerminalLogEntry represents an entry in the MSG_SYS_TERMINAL_LOG packet.
type TerminalLogEntry struct {
// Unknown fields
U0, U1, U2, U3, U4, U5, U6, U7, U8 uint32
Index uint32
Type1 uint8
Type2 uint8
Data []int16
}
// MsgSysTerminalLog represents the MSG_SYS_TERMINAL_LOG
@@ -37,15 +39,12 @@ func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client
for i := 0; i < int(m.EntryCount); i++ {
e := &TerminalLogEntry{}
e.U0 = bf.ReadUint32()
e.U1 = bf.ReadUint32()
e.U2 = bf.ReadUint32()
e.U3 = bf.ReadUint32()
e.U4 = bf.ReadUint32()
e.U5 = bf.ReadUint32()
e.U6 = bf.ReadUint32()
e.U7 = bf.ReadUint32()
e.U8 = bf.ReadUint32()
e.Index = bf.ReadUint32()
e.Type1 = bf.ReadUint8()
e.Type2 = bf.ReadUint8()
for j := 0; j < 15; j++ {
e.Data = append(e.Data, bf.ReadInt16())
}
m.Entries = append(m.Entries, e)
}

View File

@@ -2,6 +2,8 @@ package mhfpacket
import (
"errors"
ps "erupe-ce/common/pascalstring"
"golang.org/x/exp/slices"
"erupe-ce/common/byteframe"
"erupe-ce/network"
@@ -34,6 +36,12 @@ type ClientRight struct {
Timestamp uint32
}
type Course struct {
Aliases []string
ID uint16
Value uint32
}
// MsgSysUpdateRight represents the MSG_SYS_UPDATE_RIGHT
type MsgSysUpdateRight struct {
ClientRespAckHandle uint32 // If non-0, requests the client to send back a MSG_SYS_ACK packet with this value.
@@ -63,9 +71,40 @@ func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame, ctx *clientctx.Client
bf.WriteUint16(v.Unk0)
bf.WriteUint32(v.Timestamp)
}
bf.WriteUint16(m.UnkSize) // String of upto 0x800 bytes, update client login token / password in the game's launcherstate struct.
//bf.WriteBytes(m.UpdatedClientLoginToken)
ps.Uint16(bf, "", false) // update client login token / password in the game's launcherstate struct
return nil
}
func Courses() []Course {
var courses = []Course{
{[]string{"Trial", "TL"}, 1, 0x00000002},
{[]string{"HunterLife", "HL"}, 2, 0x00000004},
{[]string{"ExtraA", "Extra", "EX"}, 3, 0x00000008},
{[]string{"ExtraB"}, 4, 0x00000010},
{[]string{"Mobile"}, 5, 0x00000020},
{[]string{"Premium"}, 6, 0x00000040},
{[]string{"Pallone"}, 7, 0x00000080},
{[]string{"Assist", "Legend", "Rasta"}, 8, 0x00000100}, // Legend
{[]string{"Netcafe", "N", "Cafe"}, 9, 0x00000200},
{[]string{"Hiden", "Secret"}, 10, 0x00000400}, // Secret
{[]string{"HunterSupport", "HunterAid", "Support", "Royal", "Aid"}, 11, 0x00000800}, // Royal
{[]string{"NetcafeBoost", "NBoost", "Boost"}, 12, 0x00001000},
}
return courses
}
// GetCourseStruct returns a slice of Course(s) from a rights integer
func GetCourseStruct(rights uint32) []Course {
var resp []Course
s := Courses()
slices.SortStableFunc(s, func(i, j Course) bool {
return i.ID > j.ID
})
for _, course := range s {
if rights-course.Value < 0x80000000 {
resp = append(resp, course)
rights -= course.Value
}
}
return resp
}

View File

@@ -0,0 +1,9 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.feature_weapon
(
start_time timestamp without time zone NOT NULL,
featured integer NOT NULL
);
END;

View File

@@ -0,0 +1,15 @@
BEGIN;
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS pugi_outfit_1 int NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS pugi_outfit_2 int NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS pugi_outfit_3 int NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS pugi_outfits int NOT NULL DEFAULT 0;
END;

View File

@@ -0,0 +1,6 @@
BEGIN;
ALTER TABLE IF EXISTS public.characters
ADD COLUMN cafe_reset timestamp without time zone;
END;

View File

@@ -27,14 +27,4 @@ CREATE TABLE IF NOT EXISTS public.cafe_accepted
character_id integer NOT NULL
);
INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity)
VALUES
(1800, 17, 0, 250),
(3600, 17, 0, 500),
(7200, 17, 0, 1000),
(10800, 17, 0, 1500),
(18000, 17, 0, 1750),
(28800, 17, 0, 3000),
(43200, 17, 0, 4000);
END;

View File

@@ -0,0 +1,37 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.user_binary
(
id serial NOT NULL PRIMARY KEY,
type2 bytea,
type3 bytea,
house_tier bytea,
house_state int,
house_password text,
house_data bytea,
house_furniture bytea,
bookshelf bytea,
gallery bytea,
tore bytea,
garden bytea,
mission bytea
);
-- Create entries for existing users
INSERT INTO public.user_binary (id) SELECT c.id FROM characters c;
-- Copy existing data
UPDATE public.user_binary
SET house_furniture = (SELECT house FROM characters WHERE user_binary.id = characters.id);
UPDATE public.user_binary
SET mission = (SELECT trophy FROM characters WHERE user_binary.id = characters.id);
-- Drop old data location
ALTER TABLE public.characters
DROP COLUMN house;
ALTER TABLE public.characters
DROP COLUMN trophy;
END;

View File

@@ -0,0 +1,23 @@
--adds world_name and land columns
BEGIN;
CREATE TABLE IF NOT EXISTS public.servers
(
server_id integer NOT NULL,
season integer NOT NULL,
current_players integer NOT NULL,
world_name text COLLATE pg_catalog."default",
world_description text,
land integer
);
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS land integer;
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS world_name text COLLATE pg_catalog."default";
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS world_description text;
END;

View File

@@ -6,7 +6,6 @@ import (
"erupe-ce/common/stringsupport"
"fmt"
"io"
"math"
"net"
"strings"
"time"
@@ -74,26 +73,16 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
}
func updateRights(s *Session) {
s.rights = uint32(0x0E)
s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&s.rights)
rights := make([]mhfpacket.ClientRight, 0)
tempRights := s.rights
for i := 30; i > 0; i-- {
right := uint32(math.Pow(2, float64(i)))
if tempRights-right < 0x80000000 {
if i == 1 {
continue
}
rights = append(rights, mhfpacket.ClientRight{ID: uint16(i), Timestamp: 0x70DB59F0})
tempRights -= right
}
rightsInt := uint32(0x0E)
s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt)
s.courses = mhfpacket.GetCourseStruct(rightsInt)
rights := []mhfpacket.ClientRight{{1, 0, 0}}
for _, course := range s.courses {
rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0})
}
rights = append(rights, mhfpacket.ClientRight{ID: 1, Timestamp: 0})
update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0,
Bitfield: s.rights,
Bitfield: rightsInt,
Rights: rights,
UnkSize: 0,
}
@@ -118,9 +107,14 @@ func handleMsgSysAck(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysTerminalLog)
for i := range pkt.Entries {
s.server.logger.Info("SysTerminalLog",
zap.Uint8("Type1", pkt.Entries[i].Type1),
zap.Uint8("Type2", pkt.Entries[i].Type2),
zap.Int16s("Data", pkt.Entries[i].Data))
}
resp := byteframe.NewByteFrame()
resp.WriteUint32(0x98bd51a9) // LogID to use for requests after this.
resp.WriteUint32(pkt.LogID + 1) // LogID to use for requests after this.
doAckSimpleSucceed(s, pkt.AckHandle, resp.Data())
}
@@ -177,11 +171,29 @@ func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) {
}
func logoutPlayer(s *Session) {
s.server.Lock()
if _, exists := s.server.sessions[s.rawConn]; exists {
delete(s.server.sessions, s.rawConn)
s.rawConn.Close()
} else {
return // Prevent re-running logout logic on real logouts
}
s.rawConn.Close()
s.server.Unlock()
for _, stage := range s.server.stages {
// Tell sessions registered to disconnecting players quest to unregister
if stage.host != nil && stage.host.charID == s.charID {
for _, sess := range s.server.sessions {
for rSlot := range stage.reservedClientSlots {
if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" {
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
}
}
}
}
for session := range stage.clients {
if session.charID == s.charID {
delete(stage.clients, session)
}
}
}
_, err := s.server.db.Exec("UPDATE sign_sessions SET server_id=NULL, char_id=NULL WHERE token=$1", s.token)
@@ -201,7 +213,7 @@ func logoutPlayer(s *Session) {
timePlayed += sessionTime
var rpGained int
if s.rights >= 0x40000000 { // N Course
if s.FindCourse("Netcafe").ID != 0 {
rpGained = timePlayed / 900
timePlayed = timePlayed % 900
} else {
@@ -235,17 +247,11 @@ func logoutPlayer(s *Session) {
saveData, err := GetCharacterSaveData(s, s.charID)
if err != nil {
panic(err)
s.logger.Error("Failed to get savedata")
return
}
saveData.RP += uint16(rpGained)
transaction, err := s.server.db.Begin()
err = saveData.Save(s, transaction)
if err != nil {
transaction.Rollback()
panic(err)
} else {
transaction.Commit()
}
saveData.Save(s)
}
func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {}
@@ -754,6 +760,7 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(gook.NameLen)
bf.WriteBytes(gook.Name)
s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=$1 WHERE id=$2", gook.Index), bf.Data(), s.charID)
dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", gook.Index))
}
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
@@ -1749,6 +1756,7 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
byteInd := (bit / 8)
bitInByte := bit % 8
data[startByte+byteInd] |= bits.Reverse8((1 << uint(bitInByte)))
dumpSaveData(s, data, "skinhist")
_, err = s.server.db.Exec("UPDATE characters SET skin_hist=$1 WHERE id=$2", data, s.charID)
if err != nil {
panic(err)
@@ -1758,8 +1766,9 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfGetUdShopCoin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdShopCoin)
data, _ := hex.DecodeString("0000000000000001")
doAckBufSucceed(s, pkt.AckHandle, data)
bf := byteframe.NewByteFrame()
bf.WriteUint32(0)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}
func handleMsgMhfUseUdShopCoin(s *Session, p mhfpacket.MHFPacket) {}
@@ -1778,6 +1787,7 @@ func handleMsgMhfGetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetEnhancedMinidata)
dumpSaveData(s, pkt.RawDataPayload, "minidata")
_, err := s.server.db.Exec("UPDATE characters SET minidata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil {
s.logger.Fatal("Failed to update minidata in db", zap.Error(err))
@@ -1792,9 +1802,7 @@ func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) {
// It can be worried about later if we ever get to the point where there are
// full servers to actually need to migrate people from and empty ones to
pkt := p.(*mhfpacket.MsgMhfGetLobbyCrowd)
blankData := make([]byte, 0x320)
doAckBufSucceed(s, pkt.AckHandle, blankData)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x320))
}
func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) {

View File

@@ -4,6 +4,7 @@ import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
"fmt"
"go.uber.org/zap"
"io"
"time"
@@ -71,15 +72,22 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetCafeDuration)
bf := byteframe.NewByteFrame()
var cafeReset time.Time
err := s.server.db.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.charID).Scan(&cafeReset)
if Time_Current_Adjusted().After(cafeReset) {
cafeReset = TimeWeekNext()
s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2; DELETE FROM cafe_accepted WHERE character_id=$2`, cafeReset, s.charID)
}
var cafeTime uint32
err := s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime)
err = s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime)
if err != nil {
panic(err)
}
cafeTime = uint32(Time_Current_Adjusted().Unix()) - uint32(s.sessionStart) + cafeTime
bf.WriteUint32(cafeTime) // Total cafe time
bf.WriteUint16(0)
ps.Uint16(bf, "Resets at next maintenance", true)
ps.Uint16(bf, fmt.Sprintf("Resets on %s %d", cafeReset.Month().String(), cafeReset.Day()), true)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}

View File

@@ -1,21 +1,26 @@
package channelserver
import (
"encoding/hex"
"erupe-ce/common/byteframe"
"erupe-ce/config"
"erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket"
"fmt"
"golang.org/x/exp/slices"
"math"
"math/rand"
"strings"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
)
// MSG_SYS_CAST[ED]_BINARY types enum
const (
BinaryMessageTypeState = 0
BinaryMessageTypeChat = 1
BinaryMessageTypeQuest = 2
BinaryMessageTypeData = 3
BinaryMessageTypeMailNotify = 4
BinaryMessageTypeEmote = 6
@@ -29,6 +34,28 @@ const (
BroadcastTypeWorld = 0x0a
)
var commands map[string]config.Command
func init() {
commands = make(map[string]config.Command)
zapLogger, _ := zap.NewDevelopment()
defer zapLogger.Sync()
logger := zapLogger.Named("commands")
cmds := config.ErupeConfig.Commands
for _, cmd := range cmds {
commands[cmd.Name] = cmd
if cmd.Enabled {
logger.Info(fmt.Sprintf("%s command is enabled, prefix: %s", cmd.Name, cmd.Prefix))
} else {
logger.Info(fmt.Sprintf("%s command is disabled", cmd.Name))
}
}
}
func sendDisabledCommandMessage(s *Session, cmd config.Command) {
sendServerChatMessage(s, fmt.Sprintf("%s command is disabled", cmd.Name))
}
func sendServerChatMessage(s *Session, message string) {
// Make the inside of the casted binary
bf := byteframe.NewByteFrame()
@@ -64,6 +91,18 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
}
}
if s.server.erupeConfig.DevModeOptions.QuestDebugTools == true && s.server.erupeConfig.DevMode {
if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x02 && len(pkt.RawDataPayload) > 32 {
// This is only correct most of the time
tmp.ReadBytes(20)
tmp.SetLE()
x := tmp.ReadFloat32()
y := tmp.ReadFloat32()
z := tmp.ReadFloat32()
s.logger.Debug("Coord", zap.Float32s("XYZ", []float32{x, y, z}))
}
}
// Parse out the real casted binary payload
var msgBinTargeted *binpacket.MsgBinTargeted
var authorLen, msgLen uint16
@@ -165,167 +204,249 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
fmt.Printf("Got chat message: %+v\n", chatMessage)
// Flush all objects and users and reload
if strings.HasPrefix(chatMessage.Message, "!reload") {
sendServerChatMessage(s, "Reloading players...")
var temp mhfpacket.MHFPacket
deleteNotif := byteframe.NewByteFrame()
for _, object := range s.stage.objects {
if object.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
deleteNotif.WriteUint16(0x0010)
s.QueueSend(deleteNotif.Data())
time.Sleep(500 * time.Millisecond)
reloadNotif := byteframe.NewByteFrame()
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
}
for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDuplicateObject{
ObjID: obj.id,
X: obj.x,
Y: obj.y,
Z: obj.z,
Unk0: 0,
OwnerCharID: obj.ownerCharID,
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
reloadNotif.WriteUint16(0x0010)
s.QueueSend(reloadNotif.Data())
}
// Set account rights
if strings.HasPrefix(chatMessage.Message, "!rights") {
var v uint32
n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !rights n")
} else {
_, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v))
}
}
}
// Discord integration
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
}
// RAVI COMMANDS V2
if strings.HasPrefix(chatMessage.Message, "!ravi") {
if getRaviSemaphore(s) != "" {
s.server.raviente.Lock()
if !strings.HasPrefix(chatMessage.Message, "!ravi ") {
sendServerChatMessage(s, "No Raviente command specified!")
} else {
if strings.HasPrefix(chatMessage.Message, "!ravi start") {
if s.server.raviente.register.startTime == 0 {
s.server.raviente.register.startTime = s.server.raviente.register.postTime
sendServerChatMessage(s, "The Great Slaying will begin in a moment")
s.notifyRavi()
} else {
sendServerChatMessage(s, "The Great Slaying has already begun!")
if strings.HasPrefix(chatMessage.Message, commands["Reload"].Prefix) {
// Flush all objects and users and reload
if commands["Reload"].Enabled {
sendServerChatMessage(s, "Reloading players...")
var temp mhfpacket.MHFPacket
deleteNotif := byteframe.NewByteFrame()
for _, object := range s.stage.objects {
if object.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
deleteNotif.WriteUint16(0x0010)
s.QueueSend(deleteNotif.Data())
time.Sleep(500 * time.Millisecond)
reloadNotif := byteframe.NewByteFrame()
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi sm") || strings.HasPrefix(chatMessage.Message, "!ravi setmultiplier") {
var num uint16
n, numerr := fmt.Sscanf(chatMessage.Message, "!ravi sm %d", &num)
if numerr != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !ravi sm n")
} else if s.server.raviente.state.damageMultiplier == 1 {
if num > 32 {
sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x")
s.server.raviente.state.damageMultiplier = 32
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier set to %dx", num))
s.server.raviente.state.damageMultiplier = uint32(num)
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is already set to %dx!", s.server.raviente.state.damageMultiplier))
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi cm") || strings.HasPrefix(chatMessage.Message, "!ravi checkmultiplier") {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is currently %dx", s.server.raviente.state.damageMultiplier))
} else if strings.HasPrefix(chatMessage.Message, "!ravi sr") || strings.HasPrefix(chatMessage.Message, "!ravi sendres") {
if s.server.raviente.state.stateData[28] > 0 {
sendServerChatMessage(s, "Sending resurrection support!")
s.server.raviente.state.stateData[28] = 0
} else {
sendServerChatMessage(s, "Resurrection support has not been requested!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi ss") || strings.HasPrefix(chatMessage.Message, "!ravi sendsed") {
sendServerChatMessage(s, "Sending sedation support if requested!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP
} else if strings.HasPrefix(chatMessage.Message, "!ravi rs") || strings.HasPrefix(chatMessage.Message, "!ravi reqsed") {
sendServerChatMessage(s, "Requesting sedation support!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP + 12
} else {
sendServerChatMessage(s, "Raviente command not recognised!")
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
}
s.server.raviente.Unlock()
for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDuplicateObject{
ObjID: obj.id,
X: obj.x,
Y: obj.y,
Z: obj.z,
Unk0: 0,
OwnerCharID: obj.ownerCharID,
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
reloadNotif.WriteUint16(0x0010)
s.QueueSend(reloadNotif.Data())
} else {
sendServerChatMessage(s, "No one has joined the Great Slaying!")
sendDisabledCommandMessage(s, commands["Reload"])
}
}
// END RAVI COMMANDS V2
if strings.HasPrefix(chatMessage.Message, "!tele ") {
var x, y int16
n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y)
if err != nil || n != 2 {
sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"")
if strings.HasPrefix(chatMessage.Message, commands["KeyQuest"].Prefix) {
if commands["KeyQuest"].Enabled {
if strings.HasPrefix(chatMessage.Message, "!kqf get") {
sendServerChatMessage(s, fmt.Sprintf("KQF: %x", s.kqf))
} else if strings.HasPrefix(chatMessage.Message, "!kqf set") {
var hexs string
n, numerr := fmt.Sscanf(chatMessage.Message, "!kqf set %s", &hexs)
if numerr != nil || n != 1 || len(hexs) != 16 {
sendServerChatMessage(s, "Error in command. Format: !kqf set xxxxxxxxxxxxxxxx")
} else {
hexd, _ := hex.DecodeString(hexs)
s.kqf = hexd
s.kqfOverride = true
sendServerChatMessage(s, "KQF set, please switch Land/World")
}
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y))
sendDisabledCommandMessage(s, commands["KeyQuest"])
}
}
// Make the inside of the casted binary
payload := byteframe.NewByteFrame()
payload.SetLE()
payload.WriteUint8(2) // SetState type(position == 2)
payload.WriteInt16(x) // X
payload.WriteInt16(y) // Y
payloadBytes := payload.Data()
if strings.HasPrefix(chatMessage.Message, commands["Rights"].Prefix) {
// Set account rights
if commands["Rights"].Enabled {
var v uint32
n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !rights n")
} else {
_, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v))
}
}
} else {
sendDisabledCommandMessage(s, commands["Rights"])
}
}
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes,
})
if strings.HasPrefix(chatMessage.Message, commands["Course"].Prefix) {
if commands["Course"].Enabled {
var name string
n, err := fmt.Sscanf(chatMessage.Message, "!course %s", &name)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !course <name>")
} else {
name = strings.ToLower(name)
for _, course := range mhfpacket.Courses() {
for _, alias := range course.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) {
if s.FindCourse(name).Value != 0 {
ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool {
for _, alias := range c.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
return true
}
}
return false
})
if ei != -1 {
s.courses = append(s.courses[:ei], s.courses[ei+1:]...)
sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled.`, course.Aliases[0]))
}
} else {
s.courses = append(s.courses, course)
sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled.`, course.Aliases[0]))
}
var newInt uint32
for _, course := range s.courses {
newInt += course.Value
}
s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID)
updateRights(s)
} else {
sendServerChatMessage(s, fmt.Sprintf(`%s Course is locked.`, course.Aliases[0]))
}
}
}
}
}
} else {
sendDisabledCommandMessage(s, commands["Course"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["Raviente"].Prefix) {
if commands["Raviente"].Enabled {
if getRaviSemaphore(s) != "" {
s.server.raviente.Lock()
if !strings.HasPrefix(chatMessage.Message, "!ravi ") {
sendServerChatMessage(s, "No Raviente command specified!")
} else {
if strings.HasPrefix(chatMessage.Message, "!ravi start") {
if s.server.raviente.register.startTime == 0 {
s.server.raviente.register.startTime = s.server.raviente.register.postTime
sendServerChatMessage(s, "The Great Slaying will begin in a moment")
s.notifyRavi()
} else {
sendServerChatMessage(s, "The Great Slaying has already begun!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi sm") || strings.HasPrefix(chatMessage.Message, "!ravi setmultiplier") {
var num uint16
n, numerr := fmt.Sscanf(chatMessage.Message, "!ravi sm %d", &num)
if numerr != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !ravi sm n")
} else if s.server.raviente.state.damageMultiplier == 1 {
if num > 32 {
sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x")
s.server.raviente.state.damageMultiplier = 32
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier set to %dx", num))
s.server.raviente.state.damageMultiplier = uint32(num)
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is already set to %dx!", s.server.raviente.state.damageMultiplier))
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi cm") || strings.HasPrefix(chatMessage.Message, "!ravi checkmultiplier") {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is currently %dx", s.server.raviente.state.damageMultiplier))
} else if strings.HasPrefix(chatMessage.Message, "!ravi sr") || strings.HasPrefix(chatMessage.Message, "!ravi sendres") {
if s.server.raviente.state.stateData[28] > 0 {
sendServerChatMessage(s, "Sending resurrection support!")
s.server.raviente.state.stateData[28] = 0
} else {
sendServerChatMessage(s, "Resurrection support has not been requested!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi ss") || strings.HasPrefix(chatMessage.Message, "!ravi sendsed") {
sendServerChatMessage(s, "Sending sedation support if requested!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP
} else if strings.HasPrefix(chatMessage.Message, "!ravi rs") || strings.HasPrefix(chatMessage.Message, "!ravi reqsed") {
sendServerChatMessage(s, "Requesting sedation support!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP + 12
} else {
sendServerChatMessage(s, "Raviente command not recognised!")
}
}
s.server.raviente.Unlock()
} else {
sendServerChatMessage(s, "No one has joined the Great Slaying!")
}
} else {
sendDisabledCommandMessage(s, commands["Raviente"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["Teleport"].Prefix) {
if commands["Teleport"].Enabled {
var x, y int16
n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y)
if err != nil || n != 2 {
sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"")
} else {
sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y))
// Make the inside of the casted binary
payload := byteframe.NewByteFrame()
payload.SetLE()
payload.WriteUint8(2) // SetState type(position == 2)
payload.WriteInt16(x) // X
payload.WriteInt16(y) // Y
payloadBytes := payload.Data()
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes,
})
}
} else {
sendDisabledCommandMessage(s, commands["Teleport"])
}
}
}

View File

@@ -1,7 +1,6 @@
package channelserver
import (
"database/sql"
"encoding/binary"
"erupe-ce/network/mhfpacket"
@@ -10,120 +9,154 @@ import (
)
const (
CharacterSaveRPPointer = 0x22D16
pointerGender = 0x81 // +1
pointerRP = 0x22D16 // +2
pointerHouseTier = 0x1FB6C // +5
pointerHouseData = 0x1FE01 // +195
pointerBookshelfData = 0x22298 // +5576
// Gallery data also exists at 0x21578, is this the contest submission?
pointerGalleryData = 0x22320 // +1748
pointerToreData = 0x1FCB4 // +240
pointerGardenData = 0x22C58 // +68
pointerWeaponType = 0x1F715 // +1
pointerWeaponID = 0x1F60A // +2
pointerHRP = 0x1FDF6 // +2
pointerGRP = 0x1FDFC // +4
pointerKQF = 0x23D20 // +8
)
type CharacterSaveData struct {
CharID uint32
Name string
RP uint16
IsNewCharacter bool
// Use provided setter/getter
baseSaveData []byte
Gender bool
RP uint16
HouseTier []byte
HouseData []byte
BookshelfData []byte
GalleryData []byte
ToreData []byte
GardenData []byte
WeaponType uint8
WeaponID uint16
HRP uint16
GR uint16
KQF []byte
compSave []byte
decompSave []byte
}
func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) {
result, err := s.server.db.Query("SELECT id, savedata, is_new_character, name FROM characters WHERE id = $1", charID)
if err != nil {
s.logger.Error("failed to retrieve save data for character", zap.Error(err), zap.Uint32("charID", charID))
s.logger.Error("Failed to get savedata", zap.Error(err), zap.Uint32("charID", charID))
return nil, err
}
defer result.Close()
if !result.Next() {
s.logger.Error("No savedata found", zap.Uint32("charID", charID))
return nil, err
}
saveData := &CharacterSaveData{}
var compressedBaseSave []byte
if !result.Next() {
s.logger.Error("no results found for character save data", zap.Uint32("charID", charID))
return nil, err
}
err = result.Scan(&saveData.CharID, &compressedBaseSave, &saveData.IsNewCharacter, &saveData.Name)
err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name)
if err != nil {
s.logger.Error(
"failed to retrieve save data for character",
zap.Error(err),
zap.Uint32("charID", charID),
)
s.logger.Error("Failed to scan savedata", zap.Error(err), zap.Uint32("charID", charID))
return nil, err
}
if compressedBaseSave == nil {
if saveData.compSave == nil {
return saveData, nil
}
decompressedBaseSave, err := nullcomp.Decompress(compressedBaseSave)
err = saveData.Decompress()
if err != nil {
s.logger.Error("Failed to decompress savedata from db", zap.Error(err))
s.logger.Error("Failed to decompress savedata", zap.Error(err))
return nil, err
}
saveData.SetBaseSaveData(decompressedBaseSave)
saveData.updateStructWithSaveData()
return saveData, nil
}
func (save *CharacterSaveData) Save(s *Session, transaction *sql.Tx) error {
// We need to update the save data byte array before we save it back to the DB
func (save *CharacterSaveData) Save(s *Session) {
if !s.kqfOverride {
s.kqf = save.KQF
} else {
save.KQF = s.kqf
}
save.updateSaveDataWithStruct()
compressedData, err := save.CompressedBaseData(s)
err := save.Compress()
if err != nil {
return err
s.logger.Error("Failed to compress savedata", zap.Error(err))
return
}
updateSQL := "UPDATE characters SET savedata=$1, is_new_character=$3 WHERE id=$2"
if transaction != nil {
_, err = transaction.Exec(updateSQL, compressedData, save.CharID, save.IsNewCharacter)
} else {
_, err = s.server.db.Exec(updateSQL, compressedData, save.CharID, save.IsNewCharacter)
}
_, err = s.server.db.Exec(`UPDATE characters SET savedata=$1, is_new_character=false, hrp=$2, gr=$3, is_female=$4, weapon_type=$5, weapon_id=$6 WHERE id=$7
`, save.compSave, save.HRP, save.GR, save.Gender, save.WeaponType, save.WeaponID, save.CharID)
if err != nil {
s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID))
}
s.server.db.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7
`, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.charID)
}
func (save *CharacterSaveData) Compress() error {
var err error
save.compSave, err = nullcomp.Compress(save.decompSave)
if err != nil {
s.logger.Error("failed to save character data", zap.Error(err), zap.Uint32("charID", save.CharID))
return err
}
return nil
}
func (save *CharacterSaveData) CompressedBaseData(s *Session) ([]byte, error) {
compressedData, err := nullcomp.Compress(save.baseSaveData)
func (save *CharacterSaveData) Decompress() error {
var err error
save.decompSave, err = nullcomp.Decompress(save.compSave)
if err != nil {
s.logger.Error("failed to compress saveData", zap.Error(err), zap.Uint32("charID", save.CharID))
return nil, err
return err
}
return compressedData, nil
return nil
}
func (save *CharacterSaveData) BaseSaveData() []byte {
return save.baseSaveData
}
func (save *CharacterSaveData) SetBaseSaveData(data []byte) {
save.baseSaveData = data
// After setting the new save byte array, we can extract the values to update our struct
// This will be useful when we save it back, we use the struct values to overwrite the saveData
save.updateStructWithSaveData()
}
// This will update the save struct with the values stored in the raw savedata arrays
// This will update the character save with the values stored in the save struct
func (save *CharacterSaveData) updateSaveDataWithStruct() {
rpBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(rpBytes, save.RP)
copy(save.baseSaveData[CharacterSaveRPPointer:CharacterSaveRPPointer+2], rpBytes)
copy(save.decompSave[pointerRP:pointerRP+2], rpBytes)
copy(save.decompSave[pointerKQF:pointerKQF+8], save.KQF)
}
// This will update the character save struct with the values stored in the raw savedata arrays
// This will update the save struct with the values stored in the character save
func (save *CharacterSaveData) updateStructWithSaveData() {
save.RP = binary.LittleEndian.Uint16(save.baseSaveData[CharacterSaveRPPointer : CharacterSaveRPPointer+2])
if save.decompSave[pointerGender] == 1 {
save.Gender = true
} else {
save.Gender = false
}
if !save.IsNewCharacter {
save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRP : pointerRP+2])
save.HouseTier = save.decompSave[pointerHouseTier : pointerHouseTier+5]
save.HouseData = save.decompSave[pointerHouseData : pointerHouseData+195]
save.BookshelfData = save.decompSave[pointerBookshelfData : pointerBookshelfData+5576]
save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748]
save.ToreData = save.decompSave[pointerToreData : pointerToreData+240]
save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68]
save.WeaponType = save.decompSave[pointerWeaponType]
save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2])
save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2])
if save.HRP == uint16(999) {
save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4]))
}
save.KQF = save.decompSave[pointerKQF : pointerKQF+8]
}
return
}
func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {

View File

@@ -1,8 +1,8 @@
package channelserver
import (
"encoding/binary"
"encoding/hex"
"erupe-ce/common/bfutil"
"erupe-ce/common/stringsupport"
"fmt"
"io"
@@ -10,7 +10,6 @@ import (
"os"
"path/filepath"
"erupe-ce/common/bfutil"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
"erupe-ce/server/channelserver/compression/deltacomp"
@@ -26,7 +25,6 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
return
}
// Var to hold the decompressed savedata for updating the launcher response fields.
var decompressedData []byte
if pkt.SaveType == 1 {
// Diff-based update.
// diffs themselves are also potentially compressed
@@ -36,77 +34,23 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
}
// Perform diff.
s.logger.Info("Diffing...")
characterSaveData.SetBaseSaveData(deltacomp.ApplyDataDiff(diff, characterSaveData.BaseSaveData()))
characterSaveData.decompSave = deltacomp.ApplyDataDiff(diff, characterSaveData.decompSave)
} else {
dumpSaveData(s, pkt.RawDataPayload, "savedata")
// Regular blob update.
saveData, err := nullcomp.Decompress(pkt.RawDataPayload)
if err != nil {
s.logger.Fatal("Failed to decompress savedata from packet", zap.Error(err))
}
s.logger.Info("Updating save with blob")
characterSaveData.SetBaseSaveData(saveData)
}
characterSaveData.IsNewCharacter = false
characterBaseSaveData := characterSaveData.BaseSaveData()
// Make a copy for updating the launcher fields.
decompressedData = make([]byte, len(characterBaseSaveData))
copy(decompressedData, characterBaseSaveData)
err = characterSaveData.Save(s, nil)
if err != nil {
s.logger.Fatal("Failed to update savedata in db", zap.Error(err))
characterSaveData.decompSave = saveData
}
characterSaveData.updateStructWithSaveData()
characterSaveData.Save(s)
s.logger.Info("Wrote recompressed savedata back to DB.")
dumpSaveData(s, pkt.RawDataPayload, "savedata")
_, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(decompressedData[128789]), s.charID)
if err != nil {
s.logger.Fatal("Failed to character weapon type in db", zap.Error(err))
}
s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5
s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195
s.myseries.bookshelfData = decompressedData[139928:145504] // 0x22298 + 5576
// Gallery data also exists at 0x21578, is this the contest submission?
s.myseries.galleryData = decompressedData[140064:141812] // 0x22320 + 1748
s.myseries.toreData = decompressedData[130228:130468] // 0x1FCB4 + 240
s.myseries.gardenData = decompressedData[142424:142492] // 0x22C58 + 68
isFemale := decompressedData[81] // 0x51
if isFemale == 1 {
_, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID)
} else {
_, err = s.server.db.Exec("UPDATE characters SET is_female=false WHERE id=$1", s.charID)
}
if err != nil {
s.logger.Fatal("Failed to character gender in db", zap.Error(err))
}
weaponId := binary.LittleEndian.Uint16(decompressedData[128522:128524]) // 0x1F60A
_, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", weaponId, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character weapon id in db", zap.Error(err))
}
hrp := binary.LittleEndian.Uint16(decompressedData[130550:130552]) // 0x1FDF6
_, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", hrp, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character hrp in db", zap.Error(err))
}
grp := binary.LittleEndian.Uint32(decompressedData[130556:130560]) // 0x1FDFC
var gr uint16
if grp > 0 {
gr = grpToGR(grp)
} else {
gr = 0
}
_, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", gr, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character gr in db", zap.Error(err))
}
characterName := s.clientContext.StrConv.MustDecode(bfutil.UpToNull(decompressedData[88:100]))
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterName, s.charID)
characterSaveData.Name = stringsupport.SJISToUTF8(bfutil.UpToNull(characterSaveData.decompSave[88:100]))
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character name in db", zap.Error(err))
}
@@ -275,15 +219,24 @@ func dumpSaveData(s *Session, data []byte, suffix string) {
if !s.server.erupeConfig.DevModeOptions.SaveDumps.Enabled {
return
} else {
dir := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d_%s", s.charID, s.Name))
path := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d_%s", s.charID, s.Name), fmt.Sprintf("%d_%s_%s.bin", s.charID, s.Name, suffix))
if _, err := os.Stat(dir); os.IsNotExist(err) {
os.Mkdir(dir, os.ModeDir)
}
err := ioutil.WriteFile(path, data, 0644)
dir := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID))
path := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID), fmt.Sprintf("%d_%s.bin", s.charID, suffix))
_, err := os.Stat(dir)
if err != nil {
s.logger.Fatal("Error dumping savedata", zap.Error(err))
if os.IsNotExist(err) {
err = os.Mkdir(dir, os.ModeDir)
if err != nil {
s.logger.Warn("Error dumping savedata, could not create folder")
return
}
} else {
s.logger.Warn("Error dumping savedata")
return
}
}
err = os.WriteFile(path, data, 0644)
if err != nil {
s.logger.Warn("Error dumping savedata, could not write file", zap.Error(err))
}
}
}
@@ -320,7 +273,8 @@ func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveScenarioData)
_, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE characters.id = $2", pkt.RawDataPayload, int(s.charID))
dumpSaveData(s, pkt.RawDataPayload, "scenario")
_, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID)
if err != nil {
s.logger.Fatal("Failed to update scenario data in db", zap.Error(err))
}
@@ -337,7 +291,7 @@ func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadScenarioData)
var scenarioData []byte
bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE characters.id = $1", int(s.charID)).Scan(&scenarioData)
err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData)
if err != nil {
s.logger.Fatal("Failed to get scenario data contents in db", zap.Error(err))
} else {

View File

@@ -53,38 +53,46 @@ func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) {
}
type activeFeature struct {
StartTime time.Time
ActiveFeatures uint32
Unk1 uint16
StartTime time.Time `db:"start_time"`
ActiveFeatures uint32 `db:"featured"`
}
func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
persistentEventSchedule := make([]activeFeature, 8) // generate day after weekly restart
for x := -1; x < 7; x++ {
feat := generateActiveWeapons(14) // number of active weapons
// TODO: only generate this once per restart (server should be restarted weekly)
// then load data from db instead of regenerating
persistentEventSchedule[x+1] = activeFeature{
StartTime: Time_Current_Midnight().Add(time.Duration(24*x) * time.Hour),
ActiveFeatures: uint32(feat),
Unk1: 0,
var features []activeFeature
rows, _ := s.server.db.Queryx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1 OR start_time=$2`, Time_Current_Midnight().Add(-24*time.Hour), Time_Current_Midnight())
for rows.Next() {
var feature activeFeature
rows.StructScan(&feature)
features = append(features, feature)
}
if len(features) < 2 {
if len(features) == 0 {
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
feature.StartTime = Time_Current_Midnight().Add(-24 * time.Hour)
features = append(features, feature)
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
}
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
feature.StartTime = Time_Current_Midnight()
features = append(features, feature)
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
}
resp := byteframe.NewByteFrame()
resp.WriteUint8(uint8(len(persistentEventSchedule))) // Entry count, client only parses the first 7 or 8.
resp.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix())) // 5 minutes ago server time
for _, es := range persistentEventSchedule {
resp.WriteUint32(uint32(es.StartTime.Unix()))
resp.WriteUint32(es.ActiveFeatures)
resp.WriteUint16(es.Unk1)
bf := byteframe.NewByteFrame()
bf.WriteUint8(2)
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
for _, feature := range features {
bf.WriteUint32(uint32(feature.StartTime.Unix()))
bf.WriteUint32(feature.ActiveFeatures)
bf.WriteUint16(0)
}
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func generateActiveWeapons(count int) int {
func generateFeatureWeapons(count int) activeFeature {
nums := make([]int, 0)
var result int
r := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -104,7 +112,7 @@ func generateActiveWeapons(count int) int {
for _, num := range nums {
result += int(math.Pow(2, float64(num)))
}
return result
return activeFeature{ActiveFeatures: uint32(result)}
}
type loginBoost struct {

View File

@@ -6,6 +6,7 @@ import (
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
"math/rand"
"sort"
"time"
)
@@ -253,11 +254,19 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
var souls uint32
var souls, exists uint32
s.server.db.QueryRow("SELECT souls FROM guild_characters WHERE character_id=$1", s.charID).Scan(&souls)
err = s.server.db.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.charID).Scan(&exists)
bf := byteframe.NewByteFrame()
bf.WriteUint32(souls)
bf.WriteUint32(0) // unk
if err != nil {
bf.WriteBool(true)
bf.WriteBool(false)
} else {
bf.WriteBool(false)
bf.WriteBool(true)
}
bf.WriteUint16(0) // Unk
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
@@ -280,10 +289,10 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
return
}
resp.WriteUint32(guild.Souls)
resp.WriteUint32(0) // unk
resp.WriteUint32(0) // unk, rank?
resp.WriteUint32(0) // unk
resp.WriteUint32(0) // unk
resp.WriteUint32(1) // unk
resp.WriteUint32(1) // unk
resp.WriteUint32(1) // unk, rank?
resp.WriteUint32(1) // unk
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
@@ -302,6 +311,9 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(len(members)))
bf.WriteUint16(0) // Unk
sort.Slice(members, func(i, j int) bool {
return members[i].Souls > members[j].Souls
})
for _, member := range members {
bf.WriteUint32(member.CharID)
bf.WriteUint32(member.Souls)
@@ -342,6 +354,7 @@ func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFesta)
s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -368,7 +381,7 @@ type Prize struct {
func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaPersonalPrize)
rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='personal'")
rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='personal'`, s.charID)
var count uint32
prizeData := byteframe.NewByteFrame()
for rows.Next() {
@@ -394,7 +407,7 @@ func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket)
func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaIntermediatePrize)
rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='guild'")
rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='guild'`, s.charID)
var count uint32
prizeData := byteframe.NewByteFrame()
for rows.Next() {

View File

@@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"sort"
"strings"
"time"
@@ -54,6 +55,10 @@ type Guild struct {
PugiName1 string `db:"pugi_name_1"`
PugiName2 string `db:"pugi_name_2"`
PugiName3 string `db:"pugi_name_3"`
PugiOutfit1 uint8 `db:"pugi_outfit_1"`
PugiOutfit2 uint8 `db:"pugi_outfit_2"`
PugiOutfit3 uint8 `db:"pugi_outfit_3"`
PugiOutfits uint32 `db:"pugi_outfits"`
Recruiting bool `db:"recruiting"`
FestivalColour FestivalColour `db:"festival_colour"`
Souls uint32 `db:"souls"`
@@ -125,6 +130,10 @@ SELECT
COALESCE(pugi_name_1, '') AS pugi_name_1,
COALESCE(pugi_name_2, '') AS pugi_name_2,
COALESCE(pugi_name_3, '') AS pugi_name_3,
pugi_outfit_1,
pugi_outfit_2,
pugi_outfit_3,
pugi_outfits,
recruiting,
COALESCE((SELECT team FROM festa_registrations fr WHERE fr.guild_id = g.id), 'none') AS festival_colour,
(SELECT SUM(souls) FROM guild_characters gc WHERE gc.guild_id = g.id) AS souls,
@@ -151,8 +160,10 @@ SELECT
func (guild *Guild) Save(s *Session) error {
_, err := s.server.db.Exec(`
UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7, icon=$8, leader_id=$9 WHERE id=$1
`, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3, guild.Icon, guild.GuildLeader.LeaderCharID)
UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7,
pugi_outfit_1=$8, pugi_outfit_2=$9, pugi_outfit_3=$10, pugi_outfits=$11, icon=$12, leader_id=$13 WHERE id=$1
`, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3,
guild.PugiOutfit1, guild.PugiOutfit2, guild.PugiOutfit3, guild.PugiOutfits, guild.Icon, guild.GuildLeader.LeaderCharID)
if err != nil {
s.logger.Error("failed to update guild data", zap.Error(err), zap.Uint32("guildID", guild.ID))
@@ -164,7 +175,7 @@ func (guild *Guild) Save(s *Session) error {
func (guild *Guild) CreateApplication(s *Session, charID uint32, applicationType GuildApplicationType, transaction *sql.Tx) error {
sql := `
query := `
INSERT INTO guild_applications (guild_id, character_id, actor_id, application_type)
VALUES ($1, $2, $3, $4)
`
@@ -172,9 +183,9 @@ func (guild *Guild) CreateApplication(s *Session, charID uint32, applicationType
var err error
if transaction == nil {
_, err = s.server.db.Exec(sql, guild.ID, charID, s.charID, applicationType)
_, err = s.server.db.Exec(query, guild.ID, charID, s.charID, applicationType)
} else {
_, err = transaction.Exec(sql, guild.ID, charID, s.charID, applicationType)
_, err = transaction.Exec(query, guild.ID, charID, s.charID, applicationType)
}
if err != nil {
@@ -222,7 +233,7 @@ func (guild *Guild) Disband(s *Session) error {
return err
}
_, err = transaction.Exec("UPDATE guild_alliances SET sub1_id=NULL WHERE sub1_id=$1", guild.ID)
_, err = transaction.Exec("UPDATE guild_alliances SET sub1_id=sub2_id, sub2_id=NULL WHERE sub1_id=$1", guild.ID)
if err != nil {
s.logger.Error("failed to remove guild from alliance", zap.Error(err), zap.Uint32("guildID", guild.ID))
@@ -634,11 +645,8 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
}
bf.WriteUint32(uint32(response))
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
return
case mhfpacket.OPERATE_GUILD_RESIGN:
guildMembers, err := GetGuildMembers(s, guild.ID, false)
success := false
if err == nil {
sort.Slice(guildMembers[:], func(i, j int) bool {
return guildMembers[i].OrderIndex < guildMembers[j].OrderIndex
@@ -651,29 +659,17 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
guildMembers[0].Save(s)
guildMembers[i].Save(s)
bf.WriteUint32(guildMembers[i].CharID)
success = true
break
}
}
guild.Save(s)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}
if !success {
bf.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
return
case mhfpacket.OPERATE_GUILD_APPLY:
err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil)
if err != nil {
// All successful acks return 0x01, assuming 0x00 is failure
bf.WriteUint32(0x00)
} else {
if err == nil {
bf.WriteUint32(guild.LeaderCharID)
}
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
return
case mhfpacket.OPERATE_GUILD_LEAVE:
var err error
@@ -698,10 +694,8 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
}
bf.WriteUint32(uint32(response))
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
return
case mhfpacket.OPERATE_GUILD_DONATE_RANK:
handleDonateRP(s, pkt, bf, guild, false)
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, false))
case mhfpacket.OPERATE_GUILD_SET_APPLICATION_DENY:
s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID)
case mhfpacket.OPERATE_GUILD_SET_APPLICATION_ALLOW:
@@ -711,46 +705,55 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE:
handleAvoidLeadershipUpdate(s, pkt, false)
case mhfpacket.OPERATE_GUILD_UPDATE_COMMENT:
pbf := byteframe.NewByteFrameFromBytes(pkt.UnkData)
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
_ = pbf.ReadUint8() // len
_ = pbf.ReadUint32()
guild.Comment = stringsupport.SJISToUTF8(pbf.ReadNullTerminatedBytes())
guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())
guild.Save(s)
case mhfpacket.OPERATE_GUILD_UPDATE_MOTTO:
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
guild.SubMotto = pkt.UnkData[3]
guild.MainMotto = pkt.UnkData[4]
_ = pkt.Data1.ReadUint16()
guild.SubMotto = pkt.Data1.ReadUint8()
guild.MainMotto = pkt.Data1.ReadUint8()
guild.Save(s)
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_1:
handleRenamePugi(s, pkt.UnkData, guild, 1)
handleRenamePugi(s, pkt.Data2, guild, 1)
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_2:
handleRenamePugi(s, pkt.UnkData, guild, 2)
handleRenamePugi(s, pkt.Data2, guild, 2)
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_3:
handleRenamePugi(s, pkt.UnkData, guild, 3)
handleRenamePugi(s, pkt.Data2, guild, 3)
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_1:
// TODO: decode guild poogie outfits
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 1)
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_2:
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 2)
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_3:
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 3)
case mhfpacket.OPERATE_GUILD_UNLOCK_OUTFIT:
// TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time
s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID)
case mhfpacket.OPERATE_GUILD_DONATE_EVENT:
handleDonateRP(s, pkt, bf, guild, true)
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, true))
case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE:
rp := uint16(pkt.Data1.ReadUint32())
var balance uint32
s.server.db.QueryRow(`UPDATE guilds SET event_rp=event_rp-$1 WHERE id=$2 RETURNING event_rp`, rp, guild.ID).Scan(&balance)
bf.WriteUint32(balance)
default:
panic(fmt.Sprintf("unhandled operate guild action '%d'", pkt.Action))
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
if len(bf.Data()) > 0 {
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} else {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
}
func handleRenamePugi(s *Session, data []byte, guild *Guild, num int) {
bf := byteframe.NewByteFrameFromBytes(data)
_ = bf.ReadUint8() // len
_ = bf.ReadUint32() // unk
func handleRenamePugi(s *Session, bf *byteframe.ByteFrame, guild *Guild, num int) {
name := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
switch num {
case 1:
@@ -763,33 +766,35 @@ func handleRenamePugi(s *Session, data []byte, guild *Guild, num int) {
guild.Save(s)
}
func handleDonateRP(s *Session, pkt *mhfpacket.MsgMhfOperateGuild, bf *byteframe.ByteFrame, guild *Guild, isEvent bool) error {
rp := binary.BigEndian.Uint16(pkt.UnkData[3:5])
func handleChangePugi(s *Session, outfit uint8, guild *Guild, num int) {
switch num {
case 1:
guild.PugiOutfit1 = outfit
case 2:
guild.PugiOutfit2 = outfit
case 3:
guild.PugiOutfit3 = outfit
}
guild.Save(s)
}
func handleDonateRP(s *Session, amount uint16, guild *Guild, isEvent bool) []byte {
bf := byteframe.NewByteFrame()
bf.WriteUint32(0)
saveData, err := GetCharacterSaveData(s, s.charID)
if err != nil {
return err
}
saveData.RP -= rp
transaction, err := s.server.db.Begin()
err = saveData.Save(s, transaction)
if err != nil {
transaction.Rollback()
return err
return bf.Data()
}
saveData.RP -= amount
saveData.Save(s)
updateSQL := "UPDATE guilds SET rank_rp = rank_rp + $1 WHERE id = $2"
if isEvent {
updateSQL = "UPDATE guilds SET event_rp = event_rp + $1 WHERE id = $2"
}
_, err = s.server.db.Exec(updateSQL, rp, guild.ID)
if err != nil {
s.logger.Error("Failed to donate rank RP to guild", zap.Error(err), zap.Uint32("guildID", guild.ID))
transaction.Rollback()
return err
} else {
transaction.Commit()
}
s.server.db.Exec(updateSQL, amount, guild.ID)
bf.Seek(0, 0)
bf.WriteUint32(uint32(saveData.RP))
return nil
return bf.Data()
}
func handleAvoidLeadershipUpdate(s *Session, pkt *mhfpacket.MsgMhfOperateGuild, avoidLeadership bool) {
@@ -952,11 +957,13 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
ps.Uint8(bf, guild.PugiName1, true)
ps.Uint8(bf, guild.PugiName2, true)
ps.Uint8(bf, guild.PugiName3, true)
// probably guild pugi properties, should be status, stamina and luck outfits
bf.WriteBytes([]byte{
0x04, 0x02, 0x03, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0x4E,
})
bf.WriteUint8(guild.PugiOutfit1)
bf.WriteUint8(guild.PugiOutfit2)
bf.WriteUint8(guild.PugiOutfit3)
bf.WriteUint8(guild.PugiOutfit1)
bf.WriteUint8(guild.PugiOutfit2)
bf.WriteUint8(guild.PugiOutfit3)
bf.WriteUint32(guild.PugiOutfits)
// Unk flags
bf.WriteUint8(0x3C) // also seen as 0x32 on JP and 0x64 on TW
@@ -1027,15 +1034,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
}
applicants, err := GetGuildMembers(s, guild.ID, true)
if err != nil {
resp := byteframe.NewByteFrame()
resp.WriteUint32(0) // Count
resp.WriteUint8(0) // Unk, read if count == 0.
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
if err != nil || characterGuildData.IsApplicant {
if err != nil || (characterGuildData != nil && !characterGuildData.CanRecruit()) {
bf.WriteUint16(0)
} else {
bf.WriteUint16(uint16(len(applicants)))
@@ -1049,7 +1048,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
bf.WriteUint16(0x0000)
bf.WriteUint16(0x0000) // lenAllianceApplications
/*
alliance application format
@@ -1095,15 +1094,16 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateGuild)
var guilds []*Guild
var alliances []*GuildAlliance
var rows *sqlx.Rows
var err error
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
switch pkt.Type {
case mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME:
bf.ReadBytes(10)
bf.ReadBytes(8)
searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()))
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2 LIMIT 11`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1111,9 +1111,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_NAME:
bf.ReadBytes(10)
bf.ReadBytes(8)
searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()))
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2 LIMIT 11`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1121,7 +1121,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_ID:
bf.ReadBytes(2)
ID := bf.ReadUint32()
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE leader_id = $1`, guildInfoSelectQuery), ID)
if err == nil {
@@ -1131,11 +1130,10 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_MEMBERS:
sorting := bf.ReadUint8()
if sorting == 1 {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
if pkt.Sorting {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
} else {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
}
if err == nil {
for rows.Next() {
@@ -1144,11 +1142,10 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION:
sorting := bf.ReadUint8()
if sorting == 1 {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
if pkt.Sorting {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
} else {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
}
if err == nil {
for rows.Next() {
@@ -1157,11 +1154,10 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_RANK:
sorting := bf.ReadUint8()
if sorting == 1 {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
if pkt.Sorting {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
} else {
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
}
if err == nil {
for rows.Next() {
@@ -1170,10 +1166,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_MOTTO:
bf.ReadBytes(2)
mainMotto := bf.ReadUint16()
subMotto := bf.ReadUint16()
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3 LIMIT 11`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1182,48 +1177,126 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
case mhfpacket.ENUMERATE_GUILD_TYPE_RECRUITING:
// Assume the player wants the newest guilds with open recruitment
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE recruiting=true ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE recruiting=true ORDER BY id DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
guilds = append(guilds, guild)
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME:
//
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME:
//
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID:
//
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS:
//
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION:
//
default:
panic(fmt.Sprintf("no handler for guild search type '%d'", pkt.Type))
}
if err != nil || guilds == nil {
if pkt.Type > 8 {
var tempAlliances []*GuildAlliance
rows, err = s.server.db.Queryx(allianceInfoSelectQuery)
if err == nil {
for rows.Next() {
alliance, _ := buildAllianceObjectFromDbResult(rows, err, s)
tempAlliances = append(tempAlliances, alliance)
}
}
switch pkt.Type {
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME:
bf.ReadBytes(8)
searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
for _, alliance := range tempAlliances {
if strings.Contains(alliance.Name, searchTerm) {
alliances = append(alliances, alliance)
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME:
bf.ReadBytes(8)
searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
for _, alliance := range tempAlliances {
if strings.Contains(alliance.ParentGuild.LeaderName, searchTerm) {
alliances = append(alliances, alliance)
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID:
ID := bf.ReadUint32()
for _, alliance := range tempAlliances {
if alliance.ParentGuild.LeaderCharID == ID {
alliances = append(alliances, alliance)
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS:
if pkt.Sorting {
sort.Slice(tempAlliances, func(i, j int) bool {
return tempAlliances[i].TotalMembers > tempAlliances[j].TotalMembers
})
} else {
sort.Slice(tempAlliances, func(i, j int) bool {
return tempAlliances[i].TotalMembers < tempAlliances[j].TotalMembers
})
}
alliances = tempAlliances
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION:
if pkt.Sorting {
sort.Slice(tempAlliances, func(i, j int) bool {
return tempAlliances[i].CreatedAt.Unix() > tempAlliances[j].CreatedAt.Unix()
})
} else {
sort.Slice(tempAlliances, func(i, j int) bool {
return tempAlliances[i].CreatedAt.Unix() < tempAlliances[j].CreatedAt.Unix()
})
}
alliances = tempAlliances
}
}
if err != nil || (guilds == nil && alliances == nil) {
stubEnumerateNoResults(s, pkt.AckHandle)
return
}
bf = byteframe.NewByteFrame()
bf.WriteUint16(uint16(len(guilds)))
bf.WriteUint8(0x01) // Unk
for _, guild := range guilds {
bf.WriteUint32(guild.ID)
bf.WriteUint32(guild.LeaderCharID)
bf.WriteUint16(guild.MemberCount)
bf.WriteUint16(0x0000) // Unk
bf.WriteUint16(guild.Rank) // OR guilds in alliance
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
ps.Uint8(bf, guild.Name, true)
ps.Uint8(bf, guild.LeaderName, true)
bf.WriteUint8(0x01) // Unk
bf.WriteBool(!guild.Recruiting)
if pkt.Type > 8 {
hasNextPage := false
if len(alliances) > 10 {
hasNextPage = true
alliances = alliances[:10]
}
bf.WriteUint16(uint16(len(alliances)))
bf.WriteBool(hasNextPage)
for _, alliance := range alliances {
bf.WriteUint32(alliance.ID)
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
bf.WriteUint16(alliance.TotalMembers)
bf.WriteUint16(0x0000)
if alliance.SubGuild1ID == 0 && alliance.SubGuild2ID == 0 {
bf.WriteUint16(1)
} else if alliance.SubGuild1ID > 0 && alliance.SubGuild2ID == 0 || alliance.SubGuild1ID == 0 && alliance.SubGuild2ID > 0 {
bf.WriteUint16(2)
} else {
bf.WriteUint16(3)
}
bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
ps.Uint8(bf, alliance.Name, true)
ps.Uint8(bf, alliance.ParentGuild.LeaderName, true)
bf.WriteUint8(0x01) // Unk
bf.WriteBool(true) // TODO: Enable GuildAlliance applications
}
} else {
hasNextPage := false
if len(guilds) > 10 {
hasNextPage = true
guilds = guilds[:10]
}
bf.WriteUint16(uint16(len(guilds)))
bf.WriteBool(hasNextPage)
for _, guild := range guilds {
bf.WriteUint32(guild.ID)
bf.WriteUint32(guild.LeaderCharID)
bf.WriteUint16(guild.MemberCount)
bf.WriteUint16(0x0000) // Unk
bf.WriteUint16(guild.Rank) // OR guilds in alliance
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
ps.Uint8(bf, guild.Name, true)
ps.Uint8(bf, guild.LeaderName, true)
bf.WriteUint8(0x01) // Unk
bf.WriteBool(!guild.Recruiting)
}
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -1712,14 +1785,29 @@ func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) {
}
func handleMsgMhfGetGuildWeeklyBonusActiveCount(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGuildWeeklyBonusActiveCount)
// Values taken from brand new guild capture
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x03))
bf := byteframe.NewByteFrame()
bf.WriteUint8(0x3C) // Active count
bf.WriteUint8(0x3C) // Current active count
bf.WriteUint8(0x00) // New active count
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGuildHuntdata)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
bf := byteframe.NewByteFrame()
switch pkt.Operation {
case 0: // Unk
doAckBufSucceed(s, pkt.AckHandle, []byte{})
case 1: // Get Huntdata
bf.WriteUint8(0) // Entries
/* Entry format
uint32 UnkID
uint32 MonID
*/
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
case 2: // Unk, controls glow
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00})
}
}
type MessageBoardPost struct {

View File

@@ -1,6 +1,8 @@
package channelserver
import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"fmt"
"time"
@@ -139,8 +141,15 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
}
case mhfpacket.OPERATE_JOINT_LEAVE:
if guild.LeaderCharID == s.charID {
// delete alliance application
// or leave alliance
if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
} else if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
} else {
s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
}
// TODO: Handle deleting Alliance applications
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {
s.logger.Warn(
"Non-owner of guild attempted alliance leave",
@@ -148,10 +157,75 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
}
case mhfpacket.OPERATE_JOINT_KICK:
if alliance.ParentGuild.LeaderCharID == s.charID {
_ = pkt.UnkData.ReadUint8()
kickedGuildID := pkt.UnkData.ReadUint32()
if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
} else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
} else {
s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {
s.logger.Warn(
"Non-owner of alliance attempted kick",
zap.Uint32("CharID", s.charID),
zap.Uint32("AllyID", alliance.ID),
)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
}
default:
panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action))
}
}
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfInfoJoint)
bf := byteframe.NewByteFrame()
alliance, err := GetAllianceData(s, pkt.AllianceID)
if err != nil {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} else {
bf.WriteUint32(alliance.ID)
bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
bf.WriteUint16(alliance.TotalMembers)
bf.WriteUint16(0x0000) // Unk
ps.Uint16(bf, alliance.Name, true)
if alliance.SubGuild1ID > 0 {
if alliance.SubGuild2ID > 0 {
bf.WriteUint8(3)
} else {
bf.WriteUint8(2)
}
} else {
bf.WriteUint8(1)
}
bf.WriteUint32(alliance.ParentGuildID)
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
bf.WriteUint16(alliance.ParentGuild.Rank)
bf.WriteUint16(alliance.ParentGuild.MemberCount)
ps.Uint16(bf, alliance.ParentGuild.Name, true)
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
if alliance.SubGuild1ID > 0 {
bf.WriteUint32(alliance.SubGuild1ID)
bf.WriteUint32(alliance.SubGuild1.LeaderCharID)
bf.WriteUint16(alliance.SubGuild1.Rank)
bf.WriteUint16(alliance.SubGuild1.MemberCount)
ps.Uint16(bf, alliance.SubGuild1.Name, true)
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
}
if alliance.SubGuild2ID > 0 {
bf.WriteUint32(alliance.SubGuild2ID)
bf.WriteUint32(alliance.SubGuild2.LeaderCharID)
bf.WriteUint16(alliance.SubGuild2.Rank)
bf.WriteUint16(alliance.SubGuild2.MemberCount)
ps.Uint16(bf, alliance.SubGuild2.Name, true)
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
}

View File

@@ -38,24 +38,26 @@ FROM warehouse
func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateInterior)
_, err := s.server.db.Exec("UPDATE characters SET house=$1 WHERE id=$2", pkt.InteriorData, s.charID)
if err != nil {
panic(err)
}
s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
type HouseData struct {
CharID uint32 `db:"id"`
HRP uint16 `db:"hrp"`
GR uint16 `db:"gr"`
Name string `db:"name"`
CharID uint32 `db:"id"`
HRP uint16 `db:"hrp"`
GR uint16 `db:"gr"`
Name string `db:"name"`
HouseState uint8 `db:"house_state"`
HousePassword string `db:"house_password"`
}
func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateHouse)
bf := byteframe.NewByteFrame()
bf.WriteUint16(0)
var houses []HouseData
houseQuery := `SELECT c.id, hrp, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password
FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE c.id=$1`
switch pkt.Method {
case 1:
var friendsList string
@@ -63,17 +65,15 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
cids := stringsupport.CSVElems(friendsList)
for _, cid := range cids {
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", cid)
row := s.server.db.QueryRowx(houseQuery, cid)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
if err == nil {
houses = append(houses, house)
}
}
case 2:
guild, err := GetGuildInfoByCharacterId(s, s.charID)
if err != nil {
if err != nil || guild == nil {
break
}
guildMembers, err := GetGuildMembers(s, guild.ID, false)
@@ -82,58 +82,48 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
}
for _, member := range guildMembers {
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", member.CharID)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
row := s.server.db.QueryRowx(houseQuery, member.CharID)
err = row.StructScan(&house)
if err == nil {
houses = append(houses, house)
}
}
case 3:
houseQuery = `SELECT c.id, hrp, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password
FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE name ILIKE $1`
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE name ILIKE $1", fmt.Sprintf(`%%%s%%`, pkt.Name))
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
houses = append(houses, house)
rows, _ := s.server.db.Queryx(houseQuery, fmt.Sprintf(`%%%s%%`, pkt.Name))
for rows.Next() {
err := rows.StructScan(&house)
if err == nil {
houses = append(houses, house)
}
}
case 4:
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", pkt.CharID)
row := s.server.db.QueryRowx(houseQuery, pkt.CharID)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
if err == nil {
houses = append(houses, house)
}
case 5: // Recent visitors
break
}
var exists int
for _, house := range houses {
for _, session := range s.server.sessions {
if session.charID == house.CharID {
exists++
bf.WriteUint32(house.CharID)
bf.WriteUint8(session.myseries.state)
if len(session.myseries.password) > 0 {
bf.WriteUint8(3)
} else {
bf.WriteUint8(0)
}
bf.WriteUint16(house.HRP)
bf.WriteUint16(house.GR)
ps.Uint8(bf, house.Name, true)
break
}
bf.WriteUint32(house.CharID)
bf.WriteUint8(house.HouseState)
if len(house.HousePassword) > 0 {
bf.WriteUint8(3)
} else {
bf.WriteUint8(0)
}
bf.WriteUint16(house.HRP)
bf.WriteUint16(house.GR)
ps.Uint8(bf, house.Name, true)
}
resp := byteframe.NewByteFrame()
resp.WriteUint16(uint16(exists))
resp.WriteBytes(bf.Data())
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
bf.Seek(0, 0)
bf.WriteUint16(uint16(len(houses)))
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
@@ -143,72 +133,89 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
// 03 = open friends
// 04 = open guild
// 05 = open friends+guild
s.myseries.state = pkt.State
s.myseries.password = pkt.Password
s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadHouse)
bf := byteframe.NewByteFrame()
var state uint8
var password string
s.server.db.QueryRow(`SELECT COALESCE(house_state, 2) as house_state, COALESCE(house_password, '') as house_password FROM user_binary WHERE id=$1
`, pkt.CharID).Scan(&state, &password)
if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass {
for _, session := range s.server.sessions {
if session.charID == pkt.CharID && pkt.Password != session.myseries.password {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
if pkt.Password != password {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
}
var furniture []byte
err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&furniture)
if err != nil {
panic(err)
if pkt.Destination != 9 && state > 2 {
allowed := false
// Friends list verification
if state == 3 || state == 5 {
var friendsList string
s.server.db.QueryRow(`SELECT friends FROM characters WHERE id=$1`, pkt.CharID).Scan(&friendsList)
cids := stringsupport.CSVElems(friendsList)
for _, cid := range cids {
if uint32(cid) == s.charID {
allowed = true
break
}
}
}
// Guild verification
if state > 3 {
ownGuild, err := GetGuildInfoByCharacterId(s, s.charID)
isApplicant, _ := ownGuild.HasApplicationForCharID(s, s.charID)
if err == nil && ownGuild != nil {
othersGuild, err := GetGuildInfoByCharacterId(s, pkt.CharID)
if err == nil && othersGuild != nil {
if othersGuild.ID == ownGuild.ID && !isApplicant {
allowed = true
}
}
}
}
if !allowed {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
}
if furniture == nil {
furniture = make([]byte, 20)
var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte
s.server.db.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1
`, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden)
if houseFurniture == nil {
houseFurniture = make([]byte, 20)
}
switch pkt.Destination {
case 3: // Others house
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.houseTier)
bf.WriteBytes(session.myseries.houseData)
bf.WriteBytes(make([]byte, 19)) // Padding?
bf.WriteBytes(furniture)
}
}
bf.WriteBytes(houseTier)
bf.WriteBytes(houseData)
bf.WriteBytes(make([]byte, 19)) // Padding?
bf.WriteBytes(houseFurniture)
case 4: // Bookshelf
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.bookshelfData)
}
}
bf.WriteBytes(bookshelf)
case 5: // Gallery
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.galleryData)
}
}
bf.WriteBytes(gallery)
case 8: // Tore
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.toreData)
}
}
bf.WriteBytes(tore)
case 9: // Own house
bf.WriteBytes(furniture)
bf.WriteBytes(houseFurniture)
case 10: // Garden
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.gardenData)
c, d := getGookData(s, pkt.CharID)
bf.WriteUint16(c)
bf.WriteUint16(0)
bf.WriteBytes(d)
}
}
bf.WriteBytes(garden)
c, d := getGookData(s, pkt.CharID)
bf.WriteUint16(c)
bf.WriteUint16(0)
bf.WriteBytes(d)
}
if len(bf.Data()) == 0 {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
@@ -219,26 +226,18 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetMyhouseInfo)
var data []byte
err := s.server.db.QueryRow("SELECT trophy FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil {
panic(err)
}
s.server.db.QueryRow(`SELECT mission FROM user_binary WHERE id=$1`, s.charID).Scan(&data)
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 9))
}
}
func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateMyhouseInfo)
_, err := s.server.db.Exec("UPDATE characters SET trophy=$1 WHERE id=$2", pkt.Unk0, s.charID)
if err != nil {
panic(err)
}
s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Unk0, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
@@ -311,6 +310,7 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
}
loadData[1] = savedSets // update set count
}
dumpSaveData(s, loadData, "decomyset")
_, err := s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", loadData, s.charID)
if err != nil {
s.logger.Fatal("Failed to update decomyset savedata in db", zap.Error(err))

View File

@@ -104,6 +104,7 @@ func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("Wrote recompressed hunternavi back to DB.")
} else {
dumpSaveData(s, pkt.RawDataPayload, "hunternavi")
// simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil {
@@ -162,6 +163,7 @@ func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveMercenary)
dumpSaveData(s, pkt.MercData, "mercenary")
if len(pkt.MercData) > 0 {
s.server.db.Exec("UPDATE characters SET savemercenary=$1 WHERE id=$2", pkt.MercData, s.charID)
}
@@ -236,19 +238,31 @@ func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
return
}
bf := byteframe.NewByteFrameFromBytes(decomp)
save := byteframe.NewByteFrame()
var catsExist uint8
save.WriteUint8(0)
cats := bf.ReadUint8()
for i := 0; i < int(cats); i++ {
dataLen := bf.ReadUint32()
catID := bf.ReadUint32()
if catID == 0 {
var nextID uint32
_ = s.server.db.QueryRow("SELECT nextval('airou_id_seq')").Scan(&nextID)
bf.Seek(-4, io.SeekCurrent)
bf.WriteUint32(nextID)
_ = s.server.db.QueryRow("SELECT nextval('airou_id_seq')").Scan(&catID)
}
exists := bf.ReadBool()
data := bf.ReadBytes(uint(dataLen) - 5)
if exists {
catsExist++
save.WriteUint32(dataLen)
save.WriteUint32(catID)
save.WriteBool(exists)
save.WriteBytes(data)
}
_ = bf.ReadBytes(uint(dataLen) - 4)
}
comp, err := nullcomp.Compress(bf.Data())
save.WriteBytes(bf.DataFromCurrent())
save.Seek(0, 0)
save.WriteUint8(catsExist)
comp, err := nullcomp.Compress(save.Data())
if err != nil {
s.logger.Error("Failed to compress airou", zap.Error(err))
} else {

View File

@@ -12,20 +12,20 @@ func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) {
var data []byte
err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil {
s.logger.Fatal("Failed to get plate data savedata from db", zap.Error(err))
s.logger.Error("Failed to get plate data savedata from db", zap.Error(err))
}
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckBufSucceed(s, pkt.AckHandle, []byte{})
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
}
func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateData)
dumpSaveData(s, pkt.RawDataPayload, "_platedata")
dumpSaveData(s, pkt.RawDataPayload, "platedata")
if pkt.IsDataDiff {
var data []byte
@@ -77,20 +77,20 @@ func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) {
var data []byte
err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil {
s.logger.Fatal("Failed to get sigil box savedata from db", zap.Error(err))
s.logger.Error("Failed to get sigil box savedata from db", zap.Error(err))
}
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckBufSucceed(s, pkt.AckHandle, []byte{})
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
}
func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateBox)
dumpSaveData(s, pkt.RawDataPayload, "_platebox")
dumpSaveData(s, pkt.RawDataPayload, "platebox")
if pkt.IsDataDiff {
var data []byte
@@ -156,7 +156,7 @@ func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateMyset)
// looks to always return the full thing, simply update database, no extra processing
dumpSaveData(s, pkt.RawDataPayload, "platemyset")
_, err := s.server.db.Exec("UPDATE characters SET platemyset=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil {
s.logger.Fatal("Failed to update platemyset savedata in db", zap.Error(err))

View File

@@ -2,7 +2,6 @@ package channelserver
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -14,14 +13,24 @@ import (
func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysGetFile)
// Debug print the request.
if pkt.IsScenario {
fmt.Printf("%+v\n", pkt.ScenarioIdentifer)
if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode {
s.logger.Debug(
"Scenario",
zap.Uint8("CategoryID", pkt.ScenarioIdentifer.CategoryID),
zap.Uint32("MainID", pkt.ScenarioIdentifer.MainID),
zap.Uint8("ChapterID", pkt.ScenarioIdentifer.ChapterID),
zap.Uint8("Flags", pkt.ScenarioIdentifer.Flags),
)
}
filename := fmt.Sprintf("%d_0_0_0_S%d_T%d_C%d", pkt.ScenarioIdentifer.CategoryID, pkt.ScenarioIdentifer.MainID, pkt.ScenarioIdentifer.Flags, pkt.ScenarioIdentifer.ChapterID)
// Read the scenario file.
data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename)))
if err != nil {
panic(err)
s.logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", s.server.erupeConfig.BinPath, filename))
// This will crash the game.
doAckBufSucceed(s, pkt.AckHandle, data)
return
}
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
@@ -32,10 +41,19 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
}
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode {
s.logger.Debug(
"Quest",
zap.String("Filename", pkt.Filename),
)
}
// Get quest file.
data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename)))
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to open quest file: quests/%s.bin", pkt.Filename))
s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename))
// This will crash the game.
doAckBufSucceed(s, pkt.AckHandle, data)
return
}
doAckBufSucceed(s, pkt.AckHandle, data)
}
@@ -55,6 +73,7 @@ func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveFavoriteQuest)
dumpSaveData(s, pkt.Data, "favquest")
s.server.db.Exec("UPDATE characters SET savefavoritequest=$1 WHERE id=$2", pkt.Data, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}

View File

@@ -3,6 +3,7 @@ package channelserver
import (
ps "erupe-ce/common/pascalstring"
"fmt"
"github.com/jmoiron/sqlx"
"io/ioutil"
"path/filepath"
@@ -15,6 +16,7 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
// saved every floor on road, holds values such as floors progressed, points etc.
// can be safely handled by the client
pkt := p.(*mhfpacket.MsgMhfSaveRengokuData)
dumpSaveData(s, pkt.RawDataPayload, "rengoku")
_, err := s.server.db.Exec("UPDATE characters SET rengokudata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil {
s.logger.Fatal("Failed to update rengokudata savedata in db", zap.Error(err))
@@ -95,20 +97,13 @@ func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, data)
}
const rengokuScoreQuery = `
SELECT max_stages_mp, max_points_mp, max_stages_sp, max_points_sp, c.name, gc.guild_id
FROM rengoku_score rs
const rengokuScoreQuery = `, c.name FROM rengoku_score rs
LEFT JOIN characters c ON c.id = rs.character_id
LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id
`
LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id `
type RengokuScore struct {
Name string `db:"name"`
GuildID int `db:"guild_id"`
MaxStagesMP uint32 `db:"max_stages_mp"`
MaxPointsMP uint32 `db:"max_points_mp"`
MaxStagesSP uint32 `db:"max_stages_sp"`
MaxPointsSP uint32 `db:"max_points_sp"`
Name string `db:"name"`
Score uint32 `db:"score"`
}
func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
@@ -120,155 +115,61 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
guild = nil
}
if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 {
if guild == nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11))
return
}
}
var score RengokuScore
var selfExist bool
i := uint32(1)
bf := byteframe.NewByteFrame()
scoreData := byteframe.NewByteFrame()
var rows *sqlx.Rows
switch pkt.Leaderboard {
case 0: // Max stage overall MP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_mp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
case 0:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s ORDER BY max_stages_mp DESC", rengokuScoreQuery))
case 1:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s ORDER BY max_points_mp DESC", rengokuScoreQuery))
case 2:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID)
case 3:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID)
case 4:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s ORDER BY max_stages_sp DESC", rengokuScoreQuery))
case 5:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s ORDER BY max_points_sp DESC", rengokuScoreQuery))
case 6:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID)
case 7:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID)
}
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.Score)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
selfExist = true
}
if i > 100 {
i++
continue
}
case 1: // Max RdP overall MP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_mp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 2: // Max stage guild MP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
case 3: // Max RdP guild MP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
case 4: // Max stage overall SP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_sp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 5: // Max RdP overall SP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_sp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 6: // Max stage guild SP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
case 7: // Max RdP guild SP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.Score)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
if !selfExist {
bf.WriteBytes(make([]byte, 10))
}
bf.WriteUint8(uint8(i) - 1)
bf.WriteBytes(scoreData.Data())

View File

@@ -19,6 +19,7 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} else {
stage := NewStage(pkt.StageID)
stage.host = s
stage.maxPlayers = uint16(pkt.PlayerCount)
s.server.stages[stage.id] = stage
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
@@ -42,6 +43,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
stage = s.server.stages[stageID]
s.server.Unlock()
stage.Lock()
stage.host = s
stage.clients[s] = s.charID
stage.Unlock()
}

View File

@@ -13,7 +13,7 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
type:
1 == TOWER_RANK_POINT,
2 == GET_OWN_TOWER_SKILL
3 == ?
3 == GET_OWN_TOWER_LEVEL_V3
4 == TOWER_TOUHA_HISTORY
5 = ?
@@ -39,8 +39,8 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
case mhfpacket.TowerInfoTypeGetOwnTowerSkill:
//data, err = hex.DecodeString("0A218EAD000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
data, err = hex.DecodeString("0A218EAD0000000000000000000000010000001C0000000500050000000000020000000000000000000000000000000000030003000000000003000500050000000300030003000300030003000200030001000300020002000300010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
case mhfpacket.TowerInfoTypeUnk3:
panic("No known response values for TowerInfoTypeUnk3")
case mhfpacket.TowerInfoTypeGetOwnTowerLevelV3:
panic("No known response values for GetOwnTowerLevelV3")
case mhfpacket.TowerInfoTypeTowerTouhaHistory:
data, err = hex.DecodeString("0A218EAD0000000000000000000000010000000000000000000000000000000000000000")
case mhfpacket.TowerInfoTypeUnk5:
@@ -58,6 +58,9 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGemInfo)
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 8))
}
func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -17,12 +17,12 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {
s.server.userBinaryPartsLock.Unlock()
var exists []byte
err := s.server.db.QueryRow("SELECT type2 FROM user_binaries WHERE id=$1", s.charID).Scan(&exists)
err := s.server.db.QueryRow("SELECT type2 FROM user_binary WHERE id=$1", s.charID).Scan(&exists)
if err != nil {
s.server.db.Exec("INSERT INTO user_binaries (id) VALUES ($1)", s.charID)
s.server.db.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.charID)
}
s.server.db.Exec(fmt.Sprintf("UPDATE user_binaries SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID)
s.server.db.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID)
msg := &mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID,
@@ -42,7 +42,7 @@ func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) {
// If we can't get the real data, try to get it from the database.
if !ok {
err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binaries WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data)
err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binary WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data)
if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
} else {

View File

@@ -1,22 +1,28 @@
package channelserver
import (
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"net"
"strings"
"sync"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/common/stringstack"
"erupe-ce/common/stringsupport"
"erupe-ce/network"
"erupe-ce/network/clientctx"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
"golang.org/x/text/encoding/japanese"
)
type packet struct {
data []byte
nonBlocking bool
}
// Session holds state for the channel server connection.
type Session struct {
sync.Mutex
@@ -24,11 +30,10 @@ type Session struct {
server *Server
rawConn net.Conn
cryptConn *network.CryptConn
sendPackets chan []byte
sendPackets chan packet
clientContext *clientctx.ClientContext
userEnteredStage bool // If the user has entered a stage before
myseries MySeries
stageID string
stage *Stage
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
@@ -37,8 +42,10 @@ type Session struct {
charID uint32
logKey []byte
sessionStart int64
rights uint32
courses []mhfpacket.Course
token string
kqf []byte
kqfOverride bool
semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet.
@@ -53,36 +60,21 @@ type Session struct {
mailList []int
// For Debuging
Name string
}
type MySeries struct {
houseTier []byte
houseData []byte
bookshelfData []byte
galleryData []byte
toreData []byte
gardenData []byte
state uint8
password string
Name string
closed bool
}
// NewSession creates a new Session type.
func NewSession(server *Server, conn net.Conn) *Session {
s := &Session{
logger: server.logger.Named(conn.RemoteAddr().String()),
server: server,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
sendPackets: make(chan []byte, 20),
clientContext: &clientctx.ClientContext{
StrConv: &stringsupport.StringConverter{
Encoding: japanese.ShiftJIS,
},
},
userEnteredStage: false,
sessionStart: Time_Current_Adjusted().Unix(),
stageMoveStack: stringstack.New(),
logger: server.logger.Named(conn.RemoteAddr().String()),
server: server,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
sendPackets: make(chan packet, 20),
clientContext: &clientctx.ClientContext{}, // Unused
sessionStart: Time_Current_Adjusted().Unix(),
stageMoveStack: stringstack.New(),
}
return s
}
@@ -100,19 +92,34 @@ func (s *Session) Start() {
// QueueSend queues a packet (raw []byte) to be sent.
func (s *Session) QueueSend(data []byte) {
bf := byteframe.NewByteFrameFromBytes(data[:2])
s.logMessage(bf.ReadUint16(), data, "Server", s.Name)
s.sendPackets <- data
s.logMessage(binary.BigEndian.Uint16(data[0:2]), data, "Server", s.Name)
select {
case s.sendPackets <- packet{data, false}:
// Enqueued data
default:
s.logger.Warn("Packet queue too full, flushing!")
var tempPackets []packet
for len(s.sendPackets) > 0 {
tempPacket := <-s.sendPackets
if !tempPacket.nonBlocking {
tempPackets = append(tempPackets, tempPacket)
}
}
for _, tempPacket := range tempPackets {
s.sendPackets <- tempPacket
}
s.sendPackets <- packet{data, false}
}
}
// QueueSendNonBlocking queues a packet (raw []byte) to be sent, dropping the packet entirely if the queue is full.
func (s *Session) QueueSendNonBlocking(data []byte) {
select {
case s.sendPackets <- data:
// Enqueued properly.
case s.sendPackets <- packet{data, true}:
// Enqueued data
default:
// Couldn't enqueue, likely something wrong with the connection.
s.logger.Warn("Dropped packet for session because of full send buffer, something is probably wrong")
s.logger.Warn("Packet queue too full, dropping!")
// Queue too full
}
}
@@ -140,29 +147,25 @@ func (s *Session) QueueAck(ackHandle uint32, data []byte) {
func (s *Session) sendLoop() {
for {
// TODO(Andoryuuta): Test making this into a buffered channel and grouping the packet together before sending.
rawPacket := <-s.sendPackets
if rawPacket == nil {
s.logger.Debug("Got nil from s.SendPackets, exiting send loop")
if s.closed {
return
}
// Make a copy of the data.
terminatedPacket := make([]byte, len(rawPacket))
copy(terminatedPacket, rawPacket)
// Append the MSG_SYS_END tailing opcode.
terminatedPacket = append(terminatedPacket, []byte{0x00, 0x10}...)
s.cryptConn.SendPacket(terminatedPacket)
pkt := <-s.sendPackets
err := s.cryptConn.SendPacket(append(pkt.data, []byte{0x00, 0x10}...))
if err != nil {
s.logger.Warn("Failed to send packet")
}
time.Sleep(10 * time.Millisecond)
}
}
func (s *Session) recvLoop() {
for {
if s.closed {
logoutPlayer(s)
return
}
pkt, err := s.cryptConn.ReadPacket()
if err == io.EOF {
s.logger.Info(fmt.Sprintf("[%s] Disconnected", s.Name))
logoutPlayer(s)
@@ -174,6 +177,7 @@ func (s *Session) recvLoop() {
return
}
s.handlePacketGroup(pkt)
time.Sleep(10 * time.Millisecond)
}
}
@@ -193,7 +197,8 @@ func (s *Session) handlePacketGroup(pktGroup []byte) {
s.logMessage(opcodeUint16, pktGroup, s.Name, "Server")
if opcode == network.MSG_SYS_LOGOUT {
s.rawConn.Close()
s.closed = true
return
}
// Get the packet parser and handler for this opcode.
mhfPkt := mhfpacket.FromOpcode(opcode)
@@ -258,3 +263,14 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data))
}
}
func (s *Session) FindCourse(name string) mhfpacket.Course {
for _, course := range s.courses {
for _, alias := range course.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
return course
}
}
}
return mhfpacket.Course{}
}

View File

@@ -46,6 +46,7 @@ type Stage struct {
// other clients expect the server to echo them back in the exact same format.
rawBinaryData map[stageBinaryKey][]byte
host *Session
maxPlayers uint16
password string
createdAt string

View File

@@ -90,6 +90,7 @@ func (s *Server) acceptClients() {
}
func (s *Server) handleEntranceServerConnection(conn net.Conn) {
defer conn.Close()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
n, err := io.ReadFull(conn, nullInit)
@@ -118,5 +119,4 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) {
cc.SendPacket(data)
// Close because we only need to send the response once.
// Any further requests from the client will come from a new connection.
conn.Close()
}

View File

@@ -25,7 +25,7 @@ func encodeServerInfo(config *config.Config, s *Server) []byte {
sid := (4096 + serverIdx*256) + 16
err := s.db.QueryRow("SELECT season FROM servers WHERE server_id=$1", sid).Scan(&season)
if err != nil {
panic(err)
season = 0
}
if si.IP == "" {
si.IP = config.Host
@@ -50,7 +50,7 @@ func encodeServerInfo(config *config.Config, s *Server) []byte {
bf.WriteUint16(ci.MaxPlayers)
err := s.db.QueryRow("SELECT current_players FROM servers WHERE server_id=$1", sid).Scan(&currentplayers)
if err != nil {
panic(err)
currentplayers = 0
}
bf.WriteUint16(currentplayers)
bf.WriteUint32(0)

View File

@@ -63,7 +63,7 @@ func (s *Server) registerDBAccount(username string, password string) error {
INSERT INTO characters (
user_id, is_female, is_new_character, name, unk_desc_string,
hrp, gr, weapon_type, last_login)
VALUES($1, False, True, '', '', 1, 0, 0, $2)`,
VALUES($1, False, True, '', '', 0, 0, 0, $2)`,
id,
uint32(time.Now().Unix()),
)
@@ -148,7 +148,7 @@ func (s *Server) getFriendsForCharacters(chars []character) []members {
if err != nil {
continue
}
for i, _ := range charFriends {
for i := range charFriends {
charFriends[i].CID = char.ID
}
friends = append(friends, charFriends...)

View File

@@ -42,13 +42,23 @@ func (s *Session) makeSignInResp(uid int) []byte {
bf := byteframe.NewByteFrame()
bf.WriteUint8(1) // resp_code
bf.WriteUint8(0) // file/patch server count
bf.WriteUint8(1) // resp_code
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" {
bf.WriteUint8(2)
} else {
bf.WriteUint8(0)
}
bf.WriteUint8(1) // entrance server count
bf.WriteUint8(uint8(len(chars))) // character count
bf.WriteUint32(0xFFFFFFFF) // login_token_number
bf.WriteBytes([]byte(token)) // login_token
bf.WriteUint32(uint32(time.Now().Unix())) // current time
if s.server.erupeConfig.DevMode {
if s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" {
ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerManifest, false)
ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerFile, false)
}
}
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false)
lastPlayed := uint32(0)
@@ -112,14 +122,22 @@ func (s *Session) makeSignInResp(uid int) []byte {
bf.WriteUint32(s.server.getLastCID(uid))
bf.WriteUint32(s.server.getUserRights(uid))
ps.Uint16(bf, "", false) // filters
bf.WriteUint32(0xCA104E20)
ps.Uint16(bf, "", false) // encryption
bf.WriteUint16(0xCA10)
bf.WriteUint16(0x4E20)
ps.Uint16(bf, "", false) // unk key
bf.WriteUint8(0x00)
bf.WriteUint32(0xCA110001)
bf.WriteUint32(0x4E200000)
bf.WriteUint32(uint32(returnExpiry.Unix()))
bf.WriteUint16(0xCA11)
bf.WriteUint16(0x0001)
bf.WriteUint16(0x4E20)
ps.Uint16(bf, "", false) // unk ipv4
if returnExpiry.Before(time.Now()) {
// Hack to make Return work while having a non-adjusted expiry
bf.WriteUint32(0)
} else {
bf.WriteUint32(uint32(returnExpiry.Unix()))
}
bf.WriteUint32(0x00000000)
bf.WriteUint32(0x0A5197DF)
bf.WriteUint32(0x0A5197DF) // unk id
mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt

View File

@@ -16,32 +16,19 @@ import (
type Session struct {
sync.Mutex
logger *zap.Logger
sid int
server *Server
rawConn *net.Conn
rawConn net.Conn
cryptConn *network.CryptConn
}
func (s *Session) fail() {
s.server.Lock()
delete(s.server.sessions, s.sid)
s.server.Unlock()
}
func (s *Session) work() {
for {
pkt, err := s.cryptConn.ReadPacket()
if err != nil {
s.fail()
return
}
err = s.handlePacket(pkt)
if err != nil {
s.fail()
return
}
pkt, err := s.cryptConn.ReadPacket()
if err != nil {
return
}
err = s.handlePacket(pkt)
if err != nil {
return
}
}
@@ -61,6 +48,7 @@ func (s *Session) handlePacket(pkt []byte) error {
case "DELETE:100":
loginTokenString := string(bf.ReadNullTerminatedBytes())
characterID := int(bf.ReadUint32())
_ = int(bf.ReadUint32()) // login_token_number
s.server.deleteCharacter(characterID, loginTokenString)
sugar.Infof("Deleted character ID: %v\n", characterID)
err := s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS
@@ -78,13 +66,13 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
reqUsername := string(bf.ReadNullTerminatedBytes())
reqPassword := string(bf.ReadNullTerminatedBytes())
reqUnk := string(bf.ReadNullTerminatedBytes())
reqSkey := string(bf.ReadNullTerminatedBytes())
s.server.logger.Info(
"Got sign in request",
zap.String("reqUsername", reqUsername),
zap.String("reqPassword", reqPassword),
zap.String("reqUnk", reqUnk),
zap.String("reqSkey", reqSkey),
)
newCharaReq := false
@@ -105,12 +93,15 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
s.logger.Info("Account not found", zap.String("reqUsername", reqUsername))
serverRespBytes = makeSignInFailureResp(SIGN_EAUTH)
// HACK(Andoryuuta): Create a new account if it doesn't exit.
s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword))
err = s.server.registerDBAccount(reqUsername, reqPassword)
if err != nil {
s.logger.Info("Error on creating new account", zap.Error(err))
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.AutoCreateAccount {
s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword))
err = s.server.registerDBAccount(reqUsername, reqPassword)
if err != nil {
s.logger.Info("Error on creating new account", zap.Error(err))
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
break
}
} else {
break
}

View File

@@ -24,7 +24,6 @@ type Server struct {
sync.Mutex
logger *zap.Logger
erupeConfig *config.Config
sid int
sessions map[int]*Session
db *sqlx.DB
listener net.Listener
@@ -36,8 +35,6 @@ func NewServer(config *Config) *Server {
s := &Server{
logger: config.Logger,
erupeConfig: config.ErupeConfig,
sid: 0,
sessions: make(map[int]*Session),
db: config.DB,
}
return s
@@ -84,20 +81,19 @@ func (s *Server) acceptClients() {
}
}
go s.handleConnection(s.sid, conn)
s.sid++
go s.handleConnection(conn)
}
}
func (s *Server) handleConnection(sid int, conn net.Conn) {
func (s *Server) handleConnection(conn net.Conn) {
s.logger.Info("Got connection to sign server", zap.String("remoteaddr", conn.RemoteAddr().String()))
defer conn.Close()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
_, err := io.ReadFull(conn, nullInit)
if err != nil {
fmt.Println(err)
conn.Close()
s.logger.Error("Error initialising sign server connection", zap.Error(err))
return
}
@@ -105,15 +101,10 @@ func (s *Server) handleConnection(sid int, conn net.Conn) {
session := &Session{
logger: s.logger,
server: s,
rawConn: &conn,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
}
// Add the session to the server's sessions map.
s.Lock()
s.sessions[sid] = session
s.Unlock()
// Do the session's work.
session.work()
}