diff --git a/README.md b/README.md index 669f37573..ede542a20 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,15 @@ -# Erupe Community Edition +# Erupe + +## Client Compatiblity +### Platforms +- PC +- PlayStation 3 +- PlayStation Vita +- Wii U (Up to Z2) +### Versions +- ZZ +- Z2 +- Z1 ## Setup @@ -6,24 +17,131 @@ If you are only looking to install Erupe, please use [a pre-compiled binary](htt If you want to modify or compile Erupe yourself, please read on. -### Requirements +## Requirements - [Go](https://go.dev/dl/) - [PostgreSQL](https://www.postgresql.org/download/) -### Installation +## 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/SCHEMA.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 - [Quest and Scenario Binary Files](https://files.catbox.moe/xf0l7w.7z) - [PewPewDojo Discord](https://discord.gg/CFnzbhQ) -- [Community FAQ Pastebin](https://pastebin.com/QqAwZSTC) + +## Configuration +This portion of the documentation goes over the `config.json` file. + +### General Configuration + +| Variable | Description | Default | Options | +|------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|---------------------------------| +| Host | The IP or host address the server is running from | 127.0.0.1 | | +| BinPath | The bin path folder is where you place files needed for various parts of the game such as scenario and quest files | bin | | +| Language | This is the language the server will run in. Only English `en` and Japanese `ja` are available, if you wish to contribute to tranlation, get in touch | en | en/jp | +| DisableSoftCrash | | false | | +| HideLoginNotice | This hides the notices that appear on login from `LoginNotices` | true | | +| LoginNotices | This is where you place notices for users, you can have multiple notices | | | +| PatchServerManifest | | | | +| PatchServerFile | | | | +| ScreenshotAPIURL | This is the URL you want user sreenshots to go to | | | +| DeleteOnSaveCorruption | This option deletes a users save from the database if they corrupt it, can be used as punishment for cheaters | false | | +| ClientMode | This tells the server what client version it should target | ZZ | Check compatible versions above | +| DevMode | This enables DevModeOptions to be configured | true | | + +### `DevModeOptions` Configuraiton + +| Variable | Description | Default | Options | +|----------------------|---------------------------------------------------------------------------------------------|----------|----------------------------------| +| AutoCreateAccount | This allows users that don't exist to auto create there account from initial login | true | | +| CleanDB | This cleans the database down | false | | +| MaxLauncherHR | This sets the launcher value to HR7 to allow you to break World HR requirements | false | | +| LogInboundMessages | This will allow inbound messages to be logged to stdout | false | | +| LogOutboundMessages | This will allow outbound messages to be logged to stdout | false | | +| MaxHexdumpLength | This is the maximum amount of hex bytes that will be dumped to stdout | 0 | | +| DivaEvent | This overrides the Diva event stage in game | 2 | 0/1/2/3/-1 | +| FestaEvent | This overrides the Hunter Festival event stage in game | 2 | 0/1/2/3/-1 | +| TournamentEvent | This overrides the Hunter Tournament event stage in game | 2 | 0/1/2/3/-1 | +| MezFesEvent | Enables whether the MezFes event & World are active | true | | +| MezFesAlt | Switches the multiplayer MezFes event | false | | +| DisableTokenCheck | This disables the random token that is generated at login from being checked, very insecure | false | | +| QuestDebugTools | Enable various quest debug logs | false | | +| EarthStatusOverride | Enables Pallone Fest, Tower and Conquest War events | 0 | 2=Conquest, 11=Pallone, 21=Tower | +| EarthIDOverride | A random event ID | 0 | | +| EarthMonsterOverride | Sets the ID of the monster targeted in the Conquest War | 0 | | +| SaveDumps.Enables | Enables save dumps to a folder that is set at `SaveDumps.OutputDir` | true | | +| SaveDumps.OutputDir | The folder that save dumps are saved to | savedata | | + +### `GameplayOptions` Configuraiton + +| Variable | Description | Default | Options | +|----------------------|-----------------------------------------------------------------------------|---------|---------| +| FeaturedWeapons | Number of Active Feature weapons to generate daily | 0 | | +| MaximumNP | Maximum number of NP held by a player | 100000 | | +| MaximumRP | Maximum number of RP held by a player | 100000 | | +| DisableLoginBoost | Disables the Login Boost system | false | | +| DisableBoostTime | Disables the daily NetCafe Boost Time | false | | +| BoostTimeDuration | The number of minutes NetCafe Boost Time lasts for | 120 | | +| GuildMealDuration | The number of minutes a Guild Meal can be activated for after cooking | 60 | | +| BonusQuestAllowance | Number of Bonus Point Quests to allow daily | 3 | | +| DailyQuestAllowance | Number of Daily Quests to allow daily | 1 | | +| MezfesSoloTickets | Number of solo tickets given weekly | 10 | | +| MezfesGroupTickets | Number of group tickets given weekly | 4 | | +| GUrgentRate | Adjusts the rate of G Urgent quests spawning | 10 | | +| GCPMultiplier | Adjusts the multiplier of GCP rewarded for quest completion | 1.00 | | +| GRPMultiplier | Adjusts the multiplier of G Rank Points rewarded for quest completion | 1.00 | | +| GSRPMultiplier | Adjusts the multiplier of G Skill Rank Points rewarded for quest completion | 1.00 | | +| GZennyMultiplier | Adjusts the multiplier of G Zenny rewarded for quest completion | 1.00 | | +| MaterialMultiplier | Adjusts the multiplier of Monster Materials rewarded for quest completion | 1.00 | | +| ExtraCarves | Grant n extra chances to carve ALL carcasses | 0 | | +| DisableHunterNavi | Disables the Hunter Navi | false | | +| EnableHiganjimaEvent | Enables the Higanjima event in the Rasta Bar | false | | +| EnableNierEvent | Enables the Nier event in the Rasta Bar | false | | +| DisableRoad | Disables the Hunting Road | false | | + +### Discord +There is limited Discord capability in Erupe. The feature allows you to replay messages from your server into a channel. +This may be either be removed or revamped in a future version. + +### Commands +There are several chat commands that can be turned on and off. Most of them are really for admins or debugging purposes. + +| Name | command | Description | Options | +|----------|----------------|--------------------------------------------|---------------------| +| Rights | !rights VALUE | Sets the rights integer for your account | | +| Teleport | !tele X,Y | Teleports user to specific x,y coordinate | | +| Reload | !reload | Reloads all users and character objects | | +| KeyQuest | !kqf FLAGS | Sets the Key Quest Flag for your character | | +| Course | !course OPTION | Enables/Disables a course for your account | HL,EX,Premium,Boost | +| PSN | !psn USERNAME | Links the specified PSN to your account | | + +### Ravi Sub Commands +| Name | command | Description | +|----------|----------------------------------|-------------------------------| +| Raviente | !ravi start | Starts Ravi Event | +| Raviente | !ravi cm / !ravi checkmultiplier | Checks Ravi Damage Multiplier | +| Raviente | !ravi ss | Send Sedation Support | +| Raviente | !ravi sr | Send Resurrection Support | +| Raviente | !ravi rs | Request Sedation Support | + + +## World `Entries` config + +| Config Item | Description | Options | +|-------------|------------------|------------------------------------------------------------| +| Type | Server type. | 1=Normal, 2=Cities, 3=Newbie, 4=Tavern, 5=Return, 6=MezFes | +| Season | Server activity. | 0=Green/Breeding, 1=Orange/Warm, 2=Blue/Cold | + +### `Recommend` +This sets the types of quest that can be ordered from a world. +* 0 = All quests +* 1 = Up to 2 star quests +* 2 = Up to 4 star quests +* 4 = All Quests in HR (Enables G Experience Tab) +* 5 = Only G rank quests +* 6 = Mini games world there is no place to order quests \ No newline at end of file diff --git a/common/mhfcourse/mhfcourse.go b/common/mhfcourse/mhfcourse.go index 13496119b..6b0936e45 100644 --- a/common/mhfcourse/mhfcourse.go +++ b/common/mhfcourse/mhfcourse.go @@ -66,7 +66,7 @@ func CourseExists(ID uint16, c []Course) bool { // GetCourseStruct returns a slice of Course(s) from a rights integer func GetCourseStruct(rights uint32) ([]Course, uint32) { - resp := []Course{{ID: 1}, {ID: 24}} + resp := []Course{{ID: 1}, {ID: 23}, {ID: 24}} s := Courses() slices.SortStableFunc(s, func(i, j Course) bool { return i.ID > j.ID diff --git a/common/stringsupport/string_convert.go b/common/stringsupport/string_convert.go index 53ed2ec69..452c85321 100644 --- a/common/stringsupport/string_convert.go +++ b/common/stringsupport/string_convert.go @@ -2,6 +2,7 @@ package stringsupport import ( "bytes" + "fmt" "io" "strconv" "strings" @@ -96,3 +97,23 @@ func CSVElems(csv string) []int { } return r } + +func CSVGetIndex(csv string, i int) int { + s := CSVElems(csv) + if i < len(s) { + return s[i] + } + return 0 +} + +func CSVSetIndex(csv string, i int, v int) string { + s := CSVElems(csv) + if i < len(s) { + s[i] = v + } + var r []string + for j := 0; j < len(s); j++ { + r = append(r, fmt.Sprintf(`%d`, s[j])) + } + return strings.Join(r, ",") +} diff --git a/config.json b/config.json index 2a62a3809..e752a93f1 100644 --- a/config.json +++ b/config.json @@ -11,6 +11,7 @@ "PatchServerFile": "", "ScreenshotAPIURL": "", "DeleteOnSaveCorruption": false, + "ClientMode": "ZZ", "DevMode": true, "DevModeOptions": { "AutoCreateAccount": true, @@ -26,21 +27,39 @@ "MezFesAlt": false, "DisableTokenCheck": false, "QuestDebugTools": false, + "EarthStatusOverride": 0, + "EarthIDOverride": 0, + "EarthMonsterOverride": 0, "SaveDumps": { "Enabled": true, - "OutputDir": "savedata" + "OutputDir": "save-backups" } }, "GameplayOptions": { "FeaturedWeapons": 1, "MaximumNP": 100000, "MaximumRP": 50000, + "MaximumFP": 120000, "DisableLoginBoost": false, "DisableBoostTime": false, "BoostTimeDuration": 120, "GuildMealDuration": 60, "BonusQuestAllowance": 3, - "DailyQuestAllowance": 1 + "DailyQuestAllowance": 1, + "MezfesSoloTickets": 10, + "MezfesGroupTickets": 4, + "GUrgentRate": 10, + "GCPMultiplier": 1.00, + "GRPMultiplier": 1.00, + "GSRPMultiplier": 1.00, + "GZennyMultiplier": 1.00, + "MaterialMultiplier": 1.00, + "ExtraCarves": 0, + "DisableHunterNavi": false, + "EnableKaijiEvent": false, + "EnableHiganjimaEvent": false, + "EnableNierEvent": false, + "DisableRoad": false }, "Discord": { "Enabled": false, diff --git a/config/config.go b/config/config.go index 1e91b24b7..78ddd9e8a 100644 --- a/config/config.go +++ b/config/config.go @@ -1,15 +1,70 @@ -package config +package _config import ( "fmt" "log" "net" "os" + "strings" "time" "github.com/spf13/viper" ) +type Mode int + +const ( + S1 Mode = iota + 1 + S15 + S2 + S25 + S3 + S35 + S4 + S5 + S55 + S6 + S7 + S8 + S85 + S9 + S10 + F1 + F2 + F3 + F4 + F5 + G1 + G2 + G3 + G31 + G32 + GG + G5 + G51 + G52 + G6 + G61 + G7 + G8 + G81 + G9 + G91 + G10 + G101 + Z1 + Z2 + ZZ +) + +var versionStrings = []string{"S1.0", "S1.5", "S2.0", "S2.5", "S3.0", "S3.5", "S4.0", "S5.0", "S5.5", "S6.0", "S7.0", + "S8.0", "S8.5", "S9", "S10", "FW.1", "FW.2", "FW.3", "FW.4", "FW.5", "G1", "G2", "G3", "G3.1", "G3.2", "GG", "G5", + "G5.1", "G5.2", "G6", "G6.1", "G7", "G8", "G8.1", "G9", "G9.1", "G10", "G10.1", "Z1", "Z2", "ZZ"} + +func (m Mode) String() string { + return versionStrings[m] +} + // Config holds the global server-wide config. type Config struct { Host string `mapstructure:"Host"` @@ -22,6 +77,8 @@ type Config struct { PatchServerFile string // File patch server override ScreenshotAPIURL string // Destination for screenshots uploaded to BBS DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion + ClientMode string + RealClientMode Mode DevMode bool DevModeOptions DevModeOptions @@ -38,20 +95,23 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { - AutoCreateAccount bool // Automatically create accounts if they don't exist - 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!) - QuestDebugTools bool // Enable various quest debug logs - SaveDumps SaveDumpOptions + AutoCreateAccount bool // Automatically create accounts if they don't exist + 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!) + QuestDebugTools bool // Enable various quest debug logs + EarthStatusOverride int32 + EarthIDOverride int32 + EarthMonsterOverride int32 + SaveDumps SaveDumpOptions } type SaveDumpOptions struct { @@ -61,15 +121,30 @@ type SaveDumpOptions struct { // GameplayOptions has various gameplay modifiers type GameplayOptions struct { - FeaturedWeapons int // Number of Active Feature weapons to generate daily - MaximumNP int // Maximum number of NP held by a player - MaximumRP uint16 // Maximum number of RP held by a player - DisableLoginBoost bool // Disables the Login Boost system - DisableBoostTime bool // Disables the daily NetCafe Boost Time - BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for - GuildMealDuration int // The number of minutes a Guild Meal can be activated for after cooking - BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily - DailyQuestAllowance uint32 // Number of Daily Quests to allow daily + FeaturedWeapons int // Number of Active Feature weapons to generate daily + MaximumNP int // Maximum number of NP held by a player + MaximumRP uint16 // Maximum number of RP held by a player + MaximumFP uint32 // Maximum number of FP held by a player + DisableLoginBoost bool // Disables the Login Boost system + DisableBoostTime bool // Disables the daily NetCafe Boost Time + BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for + GuildMealDuration int // The number of minutes a Guild Meal can be activated for after cooking + BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily + DailyQuestAllowance uint32 // Number of Daily Quests to allow daily + MezfesSoloTickets uint32 // Number of solo tickets given weekly + MezfesGroupTickets uint32 // Number of group tickets given weekly + GUrgentRate uint16 // Adjusts the rate of G Urgent quests spawning + GCPMultiplier float32 // Adjusts the multiplier of GCP rewarded for quest completion + GRPMultiplier float32 // Adjusts the multiplier of G Rank Points rewarded for quest completion + GSRPMultiplier float32 // Adjusts the multiplier of G Skill Rank Points rewarded for quest completion + GZennyMultiplier float32 // Adjusts the multiplier of G Zenny rewarded for quest completion + MaterialMultiplier float32 // Adjusts the multiplier of Monster Materials rewarded for quest completion + ExtraCarves uint16 // Grant n extra chances to carve ALL carcasses + DisableHunterNavi bool // Disables the Hunter Navi + EnableKaijiEvent bool // Enables the Kaiji event in the Rasta Bar + EnableHiganjimaEvent bool // Enables the Higanjima event in the Rasta Bar + EnableNierEvent bool // Enables the Nier event in the Rasta Bar + DisableRoad bool // Disables the Hunting Road } // Discord holds the discord integration config. @@ -154,7 +229,6 @@ func init() { if err != nil { preventClose(fmt.Sprintf("Failed to load config: %s", err.Error())) } - } // getOutboundIP4 gets the preferred outbound ip4 of this machine @@ -196,6 +270,20 @@ func LoadConfig() (*Config, error) { c.Host = getOutboundIP4().To4().String() } + for i := range versionStrings { + if strings.ToUpper(c.ClientMode) == versionStrings[i] { + c.RealClientMode = Mode(i + 1) + c.ClientMode = strings.ToUpper(c.ClientMode) + if c.RealClientMode < Z1 { + c.ClientMode += " (Debug only)" + } + } + } + if c.RealClientMode == 0 { + c.ClientMode = versionStrings[len(versionStrings)-1] + c.RealClientMode = ZZ + } + return c, nil } diff --git a/main.go b/main.go index 0f104eccf..dacd0dd18 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + _config "erupe-ce/config" "fmt" "net" "os" @@ -9,7 +10,6 @@ import ( "syscall" "time" - "erupe-ce/config" "erupe-ce/server/channelserver" "erupe-ce/server/discordbot" "erupe-ce/server/entranceserver" @@ -45,7 +45,8 @@ func main() { var err error var zapLogger *zap.Logger - if config.ErupeConfig.DevMode { + config := _config.ErupeConfig + if config.DevMode { zapLogger, _ = zap.NewDevelopment() } else { zapLogger, _ = zap.NewProduction() @@ -55,20 +56,21 @@ func main() { logger := zapLogger.Named("main") logger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit())) + logger.Info(fmt.Sprintf("Client Mode: %s (%d)", config.ClientMode, config.RealClientMode)) - if config.ErupeConfig.Database.Password == "" { + if config.Database.Password == "" { preventClose("Database password is blank") } - if net.ParseIP(config.ErupeConfig.Host) == nil { - ips, _ := net.LookupIP(config.ErupeConfig.Host) + if net.ParseIP(config.Host) == nil { + ips, _ := net.LookupIP(config.Host) for _, ip := range ips { if ip != nil { - config.ErupeConfig.Host = ip.String() + config.Host = ip.String() break } } - if net.ParseIP(config.ErupeConfig.Host) == nil { + if net.ParseIP(config.Host) == nil { preventClose("Invalid host address") } } @@ -76,10 +78,10 @@ func main() { // Discord bot var discordBot *discordbot.DiscordBot = nil - if config.ErupeConfig.Discord.Enabled { + if config.Discord.Enabled { bot, err := discordbot.NewDiscordBot(discordbot.Options{ Logger: logger, - Config: config.ErupeConfig, + Config: _config.ErupeConfig, }) if err != nil { @@ -102,11 +104,11 @@ func main() { // Create the postgres DB pool. connectString := fmt.Sprintf( "host='%s' port='%d' user='%s' password='%s' dbname='%s' sslmode=disable", - config.ErupeConfig.Database.Host, - config.ErupeConfig.Database.Port, - config.ErupeConfig.Database.User, - config.ErupeConfig.Database.Password, - config.ErupeConfig.Database.Database, + config.Database.Host, + config.Database.Port, + config.Database.User, + config.Database.Password, + config.Database.Database, ) db, err := sqlx.Open("postgres", connectString) @@ -126,7 +128,7 @@ func main() { _ = db.MustExec("DELETE FROM servers") // Clean the DB if the option is on. - if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB { + if config.DevMode && config.DevModeOptions.CleanDB { logger.Info("Database: Started clearing...") cleanDB(db) logger.Info("Database: Finished clearing") @@ -139,11 +141,11 @@ func main() { // Entrance server. var entranceServer *entranceserver.Server - if config.ErupeConfig.Entrance.Enabled { + if config.Entrance.Enabled { entranceServer = entranceserver.NewServer( &entranceserver.Config{ Logger: logger.Named("entrance"), - ErupeConfig: config.ErupeConfig, + ErupeConfig: _config.ErupeConfig, DB: db, }) err = entranceServer.Start() @@ -158,11 +160,11 @@ func main() { // Sign server. var signServer *signserver.Server - if config.ErupeConfig.Sign.Enabled { + if config.Sign.Enabled { signServer = signserver.NewServer( &signserver.Config{ Logger: logger.Named("sign"), - ErupeConfig: config.ErupeConfig, + ErupeConfig: _config.ErupeConfig, DB: db, }) err = signServer.Start() @@ -176,11 +178,11 @@ func main() { // New Sign server var newSignServer *signv2server.Server - if config.ErupeConfig.SignV2.Enabled { + if config.SignV2.Enabled { newSignServer = signv2server.NewServer( &signv2server.Config{ Logger: logger.Named("sign"), - ErupeConfig: config.ErupeConfig, + ErupeConfig: _config.ErupeConfig, DB: db, }) err = newSignServer.Start() @@ -194,23 +196,23 @@ func main() { var channels []*channelserver.Server - if config.ErupeConfig.Channel.Enabled { + if config.Channel.Enabled { channelQuery := "" si := 0 ci := 0 count := 1 - for j, ee := range config.ErupeConfig.Entrance.Entries { + for j, ee := range config.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, + ErupeConfig: _config.ErupeConfig, DB: db, DiscordBot: discordBot, }) if ee.IP == "" { - c.IP = config.ErupeConfig.Host + c.IP = config.Host } else { c.IP = ee.IP } @@ -246,7 +248,7 @@ func main() { signal.Notify(c, os.Interrupt, syscall.SIGTERM) <-c - if !config.ErupeConfig.DisableSoftCrash { + if !config.DisableSoftCrash { for i := 0; i < 10; i++ { message := fmt.Sprintf("Shutting down in %d...", 10-i) for _, c := range channels { @@ -257,21 +259,21 @@ func main() { } } - if config.ErupeConfig.Channel.Enabled { + if config.Channel.Enabled { for _, c := range channels { c.Shutdown() } } - if config.ErupeConfig.Sign.Enabled { + if config.Sign.Enabled { signServer.Shutdown() } - if config.ErupeConfig.SignV2.Enabled { + if config.SignV2.Enabled { newSignServer.Shutdown() } - if config.ErupeConfig.Entrance.Enabled { + if config.Entrance.Enabled { entranceServer.Shutdown() } @@ -285,7 +287,7 @@ func wait() { } func preventClose(text string) { - if config.ErupeConfig.DisableSoftCrash { + if _config.ErupeConfig.DisableSoftCrash { os.Exit(0) } fmt.Println("\nFailed to start Erupe:\n" + text) diff --git a/network/crypt_conn.go b/network/crypt_conn.go index 439e9e3a0..2fc302b18 100644 --- a/network/crypt_conn.go +++ b/network/crypt_conn.go @@ -3,6 +3,7 @@ package network import ( "encoding/hex" "errors" + _config "erupe-ce/config" "fmt" "io" "net" @@ -48,7 +49,14 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) { } // Now read the encrypted packet body after getting its size from the header. - encryptedPacketBody := make([]byte, cph.DataSize) + var encryptedPacketBody []byte + + // Don't know when support for this was added, works in Forward.4, doesn't work in Season 6.0 + if _config.ErupeConfig.RealClientMode < _config.F1 { + encryptedPacketBody = make([]byte, cph.DataSize) + } else { + encryptedPacketBody = make([]byte, uint32(cph.DataSize)+(uint32(cph.Pf0-0x03)*0x1000)) + } _, err = io.ReadFull(cc.conn, encryptedPacketBody) if err != nil { return nil, err @@ -56,7 +64,7 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) { // Update the key rotation before decrypting. if cph.KeyRotDelta != 0 { - cc.readKeyRot = (uint32(cph.KeyRotDelta) * (cc.readKeyRot + 1)) + cc.readKeyRot = uint32(cph.KeyRotDelta) * (cc.readKeyRot + 1) } out, combinedCheck, check0, check1, check2 := crypto.Decrypt(encryptedPacketBody, cc.readKeyRot, nil) @@ -94,7 +102,7 @@ func (cc *CryptConn) SendPacket(data []byte) error { keyRotDelta := byte(3) if keyRotDelta != 0 { - cc.sendKeyRot = (uint32(keyRotDelta) * (cc.sendKeyRot + 1)) + cc.sendKeyRot = uint32(keyRotDelta) * (cc.sendKeyRot + 1) } // Encrypt the data diff --git a/network/mhfpacket/msg_mhf_acquire_cafe_item.go b/network/mhfpacket/msg_mhf_acquire_cafe_item.go index 8dcad0b53..04e603a44 100644 --- a/network/mhfpacket/msg_mhf_acquire_cafe_item.go +++ b/network/mhfpacket/msg_mhf_acquire_cafe_item.go @@ -2,10 +2,11 @@ package mhfpacket import ( "errors" + _config "erupe-ce/config" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfAcquireCafeItem represents the MSG_MHF_ACQUIRE_CAFE_ITEM @@ -30,7 +31,11 @@ func (m *MsgMhfAcquireCafeItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl m.ItemType = bf.ReadUint16() m.ItemID = bf.ReadUint16() m.Quant = bf.ReadUint16() - m.PointCost = bf.ReadUint32() + if _config.ErupeConfig.RealClientMode >= _config.G1 { + m.PointCost = bf.ReadUint32() + } else { + m.PointCost = uint32(bf.ReadUint16()) + } m.Unk0 = bf.ReadUint16() return nil } diff --git a/network/mhfpacket/msg_mhf_acquire_item.go b/network/mhfpacket/msg_mhf_acquire_item.go index 96d96ab11..de86ce846 100644 --- a/network/mhfpacket/msg_mhf_acquire_item.go +++ b/network/mhfpacket/msg_mhf_acquire_item.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfAcquireItem represents the MSG_MHF_ACQUIRE_ITEM -type MsgMhfAcquireItem struct{} +type MsgMhfAcquireItem struct { + AckHandle uint32 + Unk0 uint16 + Length uint16 + Unk1 []uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfAcquireItem) Opcode() network.PacketID { @@ -18,7 +23,13 @@ func (m *MsgMhfAcquireItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfAcquireItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Length = bf.ReadUint16() + for i := 0; i < int(m.Length); i++ { + m.Unk1 = append(m.Unk1, bf.ReadUint32()) + } + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_acquire_tournament.go b/network/mhfpacket/msg_mhf_acquire_tournament.go index d1d293288..2e65e0984 100644 --- a/network/mhfpacket/msg_mhf_acquire_tournament.go +++ b/network/mhfpacket/msg_mhf_acquire_tournament.go @@ -1,15 +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" ) // MsgMhfAcquireTournament represents the MSG_MHF_ACQUIRE_TOURNAMENT -type MsgMhfAcquireTournament struct{} +type MsgMhfAcquireTournament struct { + AckHandle uint32 + TournamentID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfAcquireTournament) Opcode() network.PacketID { @@ -18,7 +21,9 @@ func (m *MsgMhfAcquireTournament) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfAcquireTournament) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.TournamentID = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_apply_campaign.go b/network/mhfpacket/msg_mhf_apply_campaign.go index 04f506a44..b39dab499 100644 --- a/network/mhfpacket/msg_mhf_apply_campaign.go +++ b/network/mhfpacket/msg_mhf_apply_campaign.go @@ -1,17 +1,18 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfApplyCampaign represents the MSG_MHF_APPLY_CAMPAIGN type MsgMhfApplyCampaign struct { AckHandle uint32 - Unk0 uint8 - Unk1 uint8 - Unk2 uint16 + Unk0 uint32 + Unk1 uint16 + Unk2 []byte } // Opcode returns the ID associated with this packet type. @@ -22,17 +23,13 @@ func (m *MsgMhfApplyCampaign) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfApplyCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint16() + m.Unk2 = bf.ReadBytes(16) return nil } // Build builds a binary packet from the current data. func (m *MsgMhfApplyCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint8(m.Unk0) - bf.WriteUint8(m.Unk1) - bf.WriteUint16(m.Unk2) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_caravan_my_rank.go b/network/mhfpacket/msg_mhf_caravan_my_rank.go index 3eb0074d4..d3e261caa 100644 --- a/network/mhfpacket/msg_mhf_caravan_my_rank.go +++ b/network/mhfpacket/msg_mhf_caravan_my_rank.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfCaravanMyRank represents the MSG_MHF_CARAVAN_MY_RANK -type MsgMhfCaravanMyRank struct{} +type MsgMhfCaravanMyRank struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfCaravanMyRank) Opcode() network.PacketID { @@ -18,7 +23,11 @@ func (m *MsgMhfCaravanMyRank) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfCaravanMyRank) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_caravan_my_score.go b/network/mhfpacket/msg_mhf_caravan_my_score.go index bb83d0992..dfa2333b4 100644 --- a/network/mhfpacket/msg_mhf_caravan_my_score.go +++ b/network/mhfpacket/msg_mhf_caravan_my_score.go @@ -1,15 +1,24 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfCaravanMyScore represents the MSG_MHF_CARAVAN_MY_SCORE -type MsgMhfCaravanMyScore struct{} +type MsgMhfCaravanMyScore struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 int32 + Unk3 int32 + Unk4 uint32 + Unk5 int32 + Unk6 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfCaravanMyScore) Opcode() network.PacketID { @@ -18,7 +27,15 @@ func (m *MsgMhfCaravanMyScore) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfCaravanMyScore) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadInt32() + m.Unk3 = bf.ReadInt32() + m.Unk4 = bf.ReadUint32() + m.Unk5 = bf.ReadInt32() + m.Unk6 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_caravan_ranking.go b/network/mhfpacket/msg_mhf_caravan_ranking.go index 7b5564bb6..1f86771af 100644 --- a/network/mhfpacket/msg_mhf_caravan_ranking.go +++ b/network/mhfpacket/msg_mhf_caravan_ranking.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfCaravanRanking represents the MSG_MHF_CARAVAN_RANKING -type MsgMhfCaravanRanking struct{} +type MsgMhfCaravanRanking struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfCaravanRanking) Opcode() network.PacketID { @@ -18,7 +23,11 @@ func (m *MsgMhfCaravanRanking) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfCaravanRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_entry_tournament.go b/network/mhfpacket/msg_mhf_entry_tournament.go index dbd600cab..6f6550cf0 100644 --- a/network/mhfpacket/msg_mhf_entry_tournament.go +++ b/network/mhfpacket/msg_mhf_entry_tournament.go @@ -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" ) // MsgMhfEntryTournament represents the MSG_MHF_ENTRY_TOURNAMENT -type MsgMhfEntryTournament struct{} +type MsgMhfEntryTournament struct { + AckHandle uint32 + TournamentID uint32 + Unk0 uint8 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfEntryTournament) Opcode() network.PacketID { @@ -18,7 +22,10 @@ func (m *MsgMhfEntryTournament) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEntryTournament) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.TournamentID = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_enumerate_campaign.go b/network/mhfpacket/msg_mhf_enumerate_campaign.go index a5e39a1cd..d06075077 100644 --- a/network/mhfpacket/msg_mhf_enumerate_campaign.go +++ b/network/mhfpacket/msg_mhf_enumerate_campaign.go @@ -1,17 +1,16 @@ package mhfpacket import ( + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfEnumerateCampaign represents the MSG_MHF_ENUMERATE_CAMPAIGN type MsgMhfEnumerateCampaign struct { AckHandle uint32 - Unk0 uint8 - Unk1 uint8 - Unk2 uint16 + Unk0 uint16 + Unk1 uint16 } // Opcode returns the ID associated with this packet type. @@ -22,17 +21,15 @@ func (m *MsgMhfEnumerateCampaign) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { bf.WriteUint32(m.AckHandle) - bf.WriteUint8(m.Unk0) - bf.WriteUint8(m.Unk1) - bf.WriteUint16(m.Unk2) + bf.WriteUint16(m.Unk0) + bf.WriteUint16(m.Unk1) return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_item.go b/network/mhfpacket/msg_mhf_enumerate_item.go index b12276703..fea4f3371 100644 --- a/network/mhfpacket/msg_mhf_enumerate_item.go +++ b/network/mhfpacket/msg_mhf_enumerate_item.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumerateItem represents the MSG_MHF_ENUMERATE_ITEM -type MsgMhfEnumerateItem struct{} +type MsgMhfEnumerateItem struct { + AckHandle uint32 + Unk0 uint16 + Unk1 uint16 + CampaignID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfEnumerateItem) Opcode() network.PacketID { @@ -18,7 +23,11 @@ func (m *MsgMhfEnumerateItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() + m.CampaignID = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_enumerate_quest.go b/network/mhfpacket/msg_mhf_enumerate_quest.go index 7bf1e1355..2bc7ea967 100644 --- a/network/mhfpacket/msg_mhf_enumerate_quest.go +++ b/network/mhfpacket/msg_mhf_enumerate_quest.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + _config "erupe-ce/config" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -30,7 +31,9 @@ func (m *MsgMhfEnumerateQuest) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.World = bf.ReadUint8() m.Counter = bf.ReadUint16() m.Offset = bf.ReadUint16() - m.Unk4 = bf.ReadUint8() + if _config.ErupeConfig.RealClientMode > _config.Z1 { + m.Unk4 = bf.ReadUint8() + } return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_shop.go b/network/mhfpacket/msg_mhf_enumerate_shop.go index 80ad5f432..153095db4 100644 --- a/network/mhfpacket/msg_mhf_enumerate_shop.go +++ b/network/mhfpacket/msg_mhf_enumerate_shop.go @@ -1,11 +1,12 @@ package mhfpacket -import ( - "errors" +import ( + "errors" + _config "erupe-ce/config" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumerateShop represents the MSG_MHF_ENUMERATE_SHOP @@ -31,8 +32,10 @@ func (m *MsgMhfEnumerateShop) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clie m.ShopID = bf.ReadUint32() m.Unk2 = bf.ReadUint16() m.Unk3 = bf.ReadUint8() - m.Unk4 = bf.ReadUint8() - m.Unk5 = bf.ReadUint32() + if _config.ErupeConfig.RealClientMode >= _config.G2 { + m.Unk4 = bf.ReadUint8() + m.Unk5 = bf.ReadUint32() + } return nil } diff --git a/network/mhfpacket/msg_mhf_get_break_seibatu_level_reward.go b/network/mhfpacket/msg_mhf_get_break_seibatu_level_reward.go index e6f0e9a56..601dd5cb2 100644 --- a/network/mhfpacket/msg_mhf_get_break_seibatu_level_reward.go +++ b/network/mhfpacket/msg_mhf_get_break_seibatu_level_reward.go @@ -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" ) // MsgMhfGetBreakSeibatuLevelReward represents the MSG_MHF_GET_BREAK_SEIBATU_LEVEL_REWARD -type MsgMhfGetBreakSeibatuLevelReward struct{} +type MsgMhfGetBreakSeibatuLevelReward struct { + AckHandle uint32 + Unk0 uint32 + Unk1 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetBreakSeibatuLevelReward) Opcode() network.PacketID { @@ -18,7 +22,10 @@ func (m *MsgMhfGetBreakSeibatuLevelReward) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetBreakSeibatuLevelReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_get_fixed_seibatu_ranking_table.go b/network/mhfpacket/msg_mhf_get_fixed_seibatu_ranking_table.go index 52651c9d2..2d7cbbac4 100644 --- a/network/mhfpacket/msg_mhf_get_fixed_seibatu_ranking_table.go +++ b/network/mhfpacket/msg_mhf_get_fixed_seibatu_ranking_table.go @@ -1,15 +1,22 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetFixedSeibatuRankingTable represents the MSG_MHF_GET_FIXED_SEIBATU_RANKING_TABLE -type MsgMhfGetFixedSeibatuRankingTable struct{} +type MsgMhfGetFixedSeibatuRankingTable struct { + AckHandle uint32 + Unk0 uint32 + Unk1 int32 + Unk2 int32 + Unk3 int32 + Unk4 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetFixedSeibatuRankingTable) Opcode() network.PacketID { @@ -18,7 +25,13 @@ func (m *MsgMhfGetFixedSeibatuRankingTable) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetFixedSeibatuRankingTable) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadInt32() + m.Unk2 = bf.ReadInt32() + m.Unk3 = bf.ReadInt32() + m.Unk4 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_get_gem_info.go b/network/mhfpacket/msg_mhf_get_gem_info.go index 36eb7948e..28638bfd2 100644 --- a/network/mhfpacket/msg_mhf_get_gem_info.go +++ b/network/mhfpacket/msg_mhf_get_gem_info.go @@ -11,8 +11,13 @@ import ( // MsgMhfGetGemInfo represents the MSG_MHF_GET_GEM_INFO type MsgMhfGetGemInfo struct { AckHandle uint32 - Unk uint32 - Unk1 []byte + Unk0 uint32 + Unk1 uint32 + Unk2 int32 + Unk3 int32 + Unk4 int32 + Unk5 int32 + Unk6 int32 } // Opcode returns the ID associated with this packet type. @@ -23,8 +28,13 @@ func (m *MsgMhfGetGemInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk = bf.ReadUint32() - m.Unk1 = bf.ReadBytes(24) + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadInt32() + m.Unk3 = bf.ReadInt32() + m.Unk4 = bf.ReadInt32() + m.Unk5 = bf.ReadInt32() + m.Unk6 = bf.ReadInt32() return nil } diff --git a/network/mhfpacket/msg_mhf_get_notice.go b/network/mhfpacket/msg_mhf_get_notice.go index 75e18d9d5..843e71ddc 100644 --- a/network/mhfpacket/msg_mhf_get_notice.go +++ b/network/mhfpacket/msg_mhf_get_notice.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetNotice represents the MSG_MHF_GET_NOTICE -type MsgMhfGetNotice struct{} +type MsgMhfGetNotice struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetNotice) Opcode() network.PacketID { @@ -18,7 +23,11 @@ func (m *MsgMhfGetNotice) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetNotice) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_get_ryoudama.go b/network/mhfpacket/msg_mhf_get_ryoudama.go index 2cffc3bdc..91d1566af 100644 --- a/network/mhfpacket/msg_mhf_get_ryoudama.go +++ b/network/mhfpacket/msg_mhf_get_ryoudama.go @@ -11,8 +11,8 @@ import ( // MsgMhfGetRyoudama represents the MSG_MHF_GET_RYOUDAMA type MsgMhfGetRyoudama struct { AckHandle uint32 - Unk0 uint8 - Unk1 uint8 + Request1 uint8 + Request2 uint8 GuildID uint32 Unk3 uint8 } @@ -25,8 +25,8 @@ func (m *MsgMhfGetRyoudama) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetRyoudama) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() + m.Request1 = bf.ReadUint8() + m.Request2 = bf.ReadUint8() m.GuildID = bf.ReadUint32() m.Unk3 = bf.ReadUint8() return nil diff --git a/network/mhfpacket/msg_mhf_get_seibattle.go b/network/mhfpacket/msg_mhf_get_seibattle.go index 6a7a80380..1398b477d 100644 --- a/network/mhfpacket/msg_mhf_get_seibattle.go +++ b/network/mhfpacket/msg_mhf_get_seibattle.go @@ -1,20 +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" ) // MsgMhfGetSeibattle represents the MSG_MHF_GET_SEIBATTLE type MsgMhfGetSeibattle struct { - // Communicator type, multi-format. This might be valid for only one type. AckHandle uint32 Unk0 uint8 - Unk1 uint8 - Unk2 uint32 // Some shared ID with MSG_SYS_RECORD_LOG, world ID? + Type uint8 + GuildID uint32 Unk3 uint8 Unk4 uint16 } @@ -28,8 +27,8 @@ func (m *MsgMhfGetSeibattle) Opcode() network.PacketID { func (m *MsgMhfGetSeibattle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint32() + m.Type = bf.ReadUint8() + m.GuildID = bf.ReadUint32() m.Unk3 = bf.ReadUint8() m.Unk4 = bf.ReadUint16() return nil diff --git a/network/mhfpacket/msg_mhf_get_senyu_daily_count.go b/network/mhfpacket/msg_mhf_get_senyu_daily_count.go index c4d34089e..4bc9f41d2 100644 --- a/network/mhfpacket/msg_mhf_get_senyu_daily_count.go +++ b/network/mhfpacket/msg_mhf_get_senyu_daily_count.go @@ -1,15 +1,17 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetSenyuDailyCount represents the MSG_MHF_GET_SENYU_DAILY_COUNT -type MsgMhfGetSenyuDailyCount struct{} +type MsgMhfGetSenyuDailyCount struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetSenyuDailyCount) Opcode() network.PacketID { @@ -18,7 +20,8 @@ func (m *MsgMhfGetSenyuDailyCount) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetSenyuDailyCount) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_get_tenrouirai.go b/network/mhfpacket/msg_mhf_get_tenrouirai.go index da460add9..a4784e39b 100644 --- a/network/mhfpacket/msg_mhf_get_tenrouirai.go +++ b/network/mhfpacket/msg_mhf_get_tenrouirai.go @@ -1,20 +1,21 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetTenrouirai represents the MSG_MHF_GET_TENROUIRAI type MsgMhfGetTenrouirai struct { - // Communicator type, multi-format. This might be valid for only one type. AckHandle uint32 - Unk0 uint16 - Unk1 uint32 - Unk2 uint16 + Unk0 uint8 + Unk1 uint8 + GuildID uint32 + Unk3 uint8 + Unk4 uint8 } // Opcode returns the ID associated with this packet type. @@ -25,9 +26,11 @@ func (m *MsgMhfGetTenrouirai) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetTenrouirai) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint32() - m.Unk2 = bf.ReadUint16() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.GuildID = bf.ReadUint32() + m.Unk3 = bf.ReadUint8() + m.Unk4 = bf.ReadUint8() return nil } diff --git a/network/mhfpacket/msg_mhf_get_tiny_bin.go b/network/mhfpacket/msg_mhf_get_tiny_bin.go index 8f76eb1a1..4db9b05b9 100644 --- a/network/mhfpacket/msg_mhf_get_tiny_bin.go +++ b/network/mhfpacket/msg_mhf_get_tiny_bin.go @@ -1,19 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetTinyBin represents the MSG_MHF_GET_TINY_BIN type MsgMhfGetTinyBin struct { // Communicator type, multi-format. This might be valid for only one type. AckHandle uint32 - Unk0 uint16 + Unk0 uint8 Unk1 uint8 + Unk2 uint8 } // Opcode returns the ID associated with this packet type. @@ -24,8 +25,9 @@ func (m *MsgMhfGetTinyBin) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() + m.Unk0 = bf.ReadUint8() m.Unk1 = bf.ReadUint8() + m.Unk2 = bf.ReadUint8() return nil } diff --git a/network/mhfpacket/msg_mhf_get_tower_info.go b/network/mhfpacket/msg_mhf_get_tower_info.go index a0b686485..4041e26e4 100644 --- a/network/mhfpacket/msg_mhf_get_tower_info.go +++ b/network/mhfpacket/msg_mhf_get_tower_info.go @@ -8,19 +8,8 @@ import ( "erupe-ce/network/clientctx" ) -// The server sends different responses based on these values. -const ( - TowerInfoTypeUnk0 = iota - TowerInfoTypeTowerRankPoint - TowerInfoTypeGetOwnTowerSkill - TowerInfoTypeGetOwnTowerLevelV3 - TowerInfoTypeTowerTouhaHistory - TowerInfoTypeUnk5 -) - // MsgMhfGetTowerInfo represents the MSG_MHF_GET_TOWER_INFO type MsgMhfGetTowerInfo struct { - // Communicator type, multi-format. This might be valid for only one type. AckHandle uint32 InfoType uint32 // Requested response type Unk0 uint32 diff --git a/network/mhfpacket/msg_mhf_operate_guild.go b/network/mhfpacket/msg_mhf_operate_guild.go index a79719290..96803e89c 100644 --- a/network/mhfpacket/msg_mhf_operate_guild.go +++ b/network/mhfpacket/msg_mhf_operate_guild.go @@ -11,33 +11,33 @@ import ( 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 - 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 + OperateGuildDisband = iota + 1 + OperateGuildApply + OperateGuildLeave + OperateGuildResign + OperateGuildSetApplicationDeny + OperateGuildSetApplicationAllow + OperateGuildSetAvoidLeadershipTrue + OperateGuildSetAvoidLeadershipFalse + OperateGuildUpdateComment + OperateGuildDonateRank + OperateGuildUpdateMotto + OperateGuildRenamePugi1 + OperateGuildRenamePugi2 + OperateGuildRenamePugi3 + OperateGuildChangePugi1 + OperateGuildChangePugi2 + OperateGuildChangePugi3 + OperateGuildUnlockOutfit + OperateGuildDonateRoom + OperateGuildGraduateRookie + OperateGuildDonateEvent + OperateGuildEventExchange + OperateGuildUnknown // I don't think this op exists + OperateGuildGraduateReturn + OperateGuildChangeDivaPugi1 + OperateGuildChangeDivaPugi2 + OperateGuildChangeDivaPugi3 ) // MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD diff --git a/network/mhfpacket/msg_mhf_post_boost_time_limit.go b/network/mhfpacket/msg_mhf_post_boost_time_limit.go index 3f0bc53b8..259712ac8 100644 --- a/network/mhfpacket/msg_mhf_post_boost_time_limit.go +++ b/network/mhfpacket/msg_mhf_post_boost_time_limit.go @@ -1,15 +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" ) // MsgMhfPostBoostTimeLimit represents the MSG_MHF_POST_BOOST_TIME_LIMIT -type MsgMhfPostBoostTimeLimit struct{} +type MsgMhfPostBoostTimeLimit struct { + AckHandle uint32 + Expiration uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfPostBoostTimeLimit) Opcode() network.PacketID { @@ -18,7 +21,9 @@ func (m *MsgMhfPostBoostTimeLimit) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostBoostTimeLimit) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Expiration = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_post_gem_info.go b/network/mhfpacket/msg_mhf_post_gem_info.go index 13a0a9a0d..d487670fc 100644 --- a/network/mhfpacket/msg_mhf_post_gem_info.go +++ b/network/mhfpacket/msg_mhf_post_gem_info.go @@ -1,15 +1,24 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfPostGemInfo represents the MSG_MHF_POST_GEM_INFO -type MsgMhfPostGemInfo struct{} +type MsgMhfPostGemInfo struct { + AckHandle uint32 + Op uint32 + Unk1 uint32 + Gem int32 + Quantity int32 + CID int32 + Message int32 + Unk6 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfPostGemInfo) Opcode() network.PacketID { @@ -18,7 +27,15 @@ func (m *MsgMhfPostGemInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Op = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Gem = bf.ReadInt32() + m.Quantity = bf.ReadInt32() + m.CID = bf.ReadInt32() + m.Message = bf.ReadInt32() + m.Unk6 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_post_notice.go b/network/mhfpacket/msg_mhf_post_notice.go index c599d2afc..51eb945fa 100644 --- a/network/mhfpacket/msg_mhf_post_notice.go +++ b/network/mhfpacket/msg_mhf_post_notice.go @@ -1,15 +1,21 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfPostNotice represents the MSG_MHF_POST_NOTICE -type MsgMhfPostNotice struct{} +type MsgMhfPostNotice struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 int32 + Unk3 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfPostNotice) Opcode() network.PacketID { @@ -18,7 +24,12 @@ func (m *MsgMhfPostNotice) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostNotice) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadInt32() + m.Unk3 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_post_tenrouirai.go b/network/mhfpacket/msg_mhf_post_tenrouirai.go index d4b4fdc71..bc91279b4 100644 --- a/network/mhfpacket/msg_mhf_post_tenrouirai.go +++ b/network/mhfpacket/msg_mhf_post_tenrouirai.go @@ -1,22 +1,34 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfPostTenrouirai represents the MSG_MHF_POST_TENROUIRAI -type MsgMhfPostTenrouirai struct{ - AckHandle uint32 - Unk0 uint16 - Unk1 uint32 - Unk2 uint32 - Unk3 uint32 - Unk4 uint32 - Unk5 uint8 +type MsgMhfPostTenrouirai struct { + AckHandle uint32 + Unk0 uint8 + Op uint8 + GuildID uint32 + Unk1 uint8 + + Floors uint16 + Antiques uint16 + Chests uint16 + Cats uint16 + TRP uint16 + Slays uint16 + + DonatedRP uint16 + PreviousRP uint16 + Unk2_0 uint16 + Unk2_1 uint16 + Unk2_2 uint16 + Unk2_3 uint16 } // Opcode returns the ID associated with this packet type. @@ -27,12 +39,28 @@ func (m *MsgMhfPostTenrouirai) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostTenrouirai) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint32() - m.Unk2 = bf.ReadUint32() - m.Unk3 = bf.ReadUint32() - m.Unk4 = bf.ReadUint32() - m.Unk5 = bf.ReadUint8() + m.Unk0 = bf.ReadUint8() + m.Op = bf.ReadUint8() + m.GuildID = bf.ReadUint32() + m.Unk1 = bf.ReadUint8() + + switch m.Op { + case 1: + m.Floors = bf.ReadUint16() + m.Antiques = bf.ReadUint16() + m.Chests = bf.ReadUint16() + m.Cats = bf.ReadUint16() + m.TRP = bf.ReadUint16() + m.Slays = bf.ReadUint16() + case 2: + m.DonatedRP = bf.ReadUint16() + m.PreviousRP = bf.ReadUint16() + m.Unk2_0 = bf.ReadUint16() + m.Unk2_1 = bf.ReadUint16() + m.Unk2_2 = bf.ReadUint16() + m.Unk2_3 = bf.ReadUint16() + } + return nil } diff --git a/network/mhfpacket/msg_mhf_post_tiny_bin.go b/network/mhfpacket/msg_mhf_post_tiny_bin.go index 7c709d1e4..dd464d18d 100644 --- a/network/mhfpacket/msg_mhf_post_tiny_bin.go +++ b/network/mhfpacket/msg_mhf_post_tiny_bin.go @@ -11,9 +11,10 @@ import ( // MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN type MsgMhfPostTinyBin struct { AckHandle uint32 - Unk0 uint16 + Unk0 uint8 Unk1 uint8 Unk2 uint8 + Unk3 uint8 Data []byte } @@ -25,9 +26,10 @@ func (m *MsgMhfPostTinyBin) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() + m.Unk0 = bf.ReadUint8() m.Unk1 = bf.ReadUint8() m.Unk2 = bf.ReadUint8() + m.Unk3 = bf.ReadUint8() m.Data = bf.ReadBytes(uint(bf.ReadUint16())) return nil } diff --git a/network/mhfpacket/msg_mhf_post_tower_info.go b/network/mhfpacket/msg_mhf_post_tower_info.go index 7719086ff..3808777e5 100644 --- a/network/mhfpacket/msg_mhf_post_tower_info.go +++ b/network/mhfpacket/msg_mhf_post_tower_info.go @@ -1,28 +1,26 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfPostTowerInfo represents the MSG_MHF_POST_TOWER_INFO type MsgMhfPostTowerInfo struct { - // Communicator type, multi-format. This might be valid for only one type. AckHandle uint32 - Unk0 uint32 + InfoType uint32 Unk1 uint32 - Unk2 uint32 - Unk3 uint32 - Unk4 uint32 - Unk5 uint32 - Unk6 uint32 - Unk7 uint32 - Unk8 uint32 - Unk9 uint32 - Unk10 uint32 + Skill int32 + TR int32 + TRP int32 + Cost int32 + Unk6 int32 + Unk7 int32 + Block1 int32 + Unk9 int64 } // Opcode returns the ID associated with this packet type. @@ -33,17 +31,16 @@ func (m *MsgMhfPostTowerInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostTowerInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() + m.InfoType = bf.ReadUint32() m.Unk1 = bf.ReadUint32() - m.Unk2 = bf.ReadUint32() - m.Unk3 = bf.ReadUint32() - m.Unk4 = bf.ReadUint32() - m.Unk5 = bf.ReadUint32() - m.Unk6 = bf.ReadUint32() - m.Unk7 = bf.ReadUint32() - m.Unk8 = bf.ReadUint32() - m.Unk9 = bf.ReadUint32() - m.Unk10 = bf.ReadUint32() + m.Skill = bf.ReadInt32() + m.TR = bf.ReadInt32() + m.TRP = bf.ReadInt32() + m.Cost = bf.ReadInt32() + m.Unk6 = bf.ReadInt32() + m.Unk7 = bf.ReadInt32() + m.Block1 = bf.ReadInt32() + m.Unk9 = bf.ReadInt64() return nil } diff --git a/network/mhfpacket/msg_mhf_present_box.go b/network/mhfpacket/msg_mhf_present_box.go index c3da92e31..d0064799c 100644 --- a/network/mhfpacket/msg_mhf_present_box.go +++ b/network/mhfpacket/msg_mhf_present_box.go @@ -18,8 +18,7 @@ type MsgMhfPresentBox struct { Unk4 uint32 Unk5 uint32 Unk6 uint32 - Unk7 uint32 - Unk8 uint32 + Unk7 []uint32 } // Opcode returns the ID associated with this packet type. @@ -37,8 +36,9 @@ func (m *MsgMhfPresentBox) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientC m.Unk4 = bf.ReadUint32() m.Unk5 = bf.ReadUint32() m.Unk6 = bf.ReadUint32() - m.Unk7 = bf.ReadUint32() - m.Unk8 = bf.ReadUint32() + for i := uint32(0); i < m.Unk2; i++ { + m.Unk7 = append(m.Unk7, bf.ReadUint32()) + } return nil } diff --git a/network/mhfpacket/msg_mhf_read_beat_level_all_ranking.go b/network/mhfpacket/msg_mhf_read_beat_level_all_ranking.go index 4d97df0d5..d9bf48a2c 100644 --- a/network/mhfpacket/msg_mhf_read_beat_level_all_ranking.go +++ b/network/mhfpacket/msg_mhf_read_beat_level_all_ranking.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfReadBeatLevelAllRanking represents the MSG_MHF_READ_BEAT_LEVEL_ALL_RANKING -type MsgMhfReadBeatLevelAllRanking struct{} +type MsgMhfReadBeatLevelAllRanking struct { + AckHandle uint32 + Unk0 uint32 + GuildID int32 + Unk2 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfReadBeatLevelAllRanking) Opcode() network.PacketID { @@ -18,7 +23,11 @@ func (m *MsgMhfReadBeatLevelAllRanking) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfReadBeatLevelAllRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.GuildID = bf.ReadInt32() + m.Unk2 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_read_beat_level_my_ranking.go b/network/mhfpacket/msg_mhf_read_beat_level_my_ranking.go index 4b713e8e7..e51bba318 100644 --- a/network/mhfpacket/msg_mhf_read_beat_level_my_ranking.go +++ b/network/mhfpacket/msg_mhf_read_beat_level_my_ranking.go @@ -1,15 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfReadBeatLevelMyRanking represents the MSG_MHF_READ_BEAT_LEVEL_MY_RANKING -type MsgMhfReadBeatLevelMyRanking struct{} +type MsgMhfReadBeatLevelMyRanking struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 []int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfReadBeatLevelMyRanking) Opcode() network.PacketID { @@ -18,7 +23,13 @@ func (m *MsgMhfReadBeatLevelMyRanking) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfReadBeatLevelMyRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + for i := 0; i < 16; i++ { + m.Unk2 = append(m.Unk2, bf.ReadInt32()) + } + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_read_last_week_beat_ranking.go b/network/mhfpacket/msg_mhf_read_last_week_beat_ranking.go index 90635dd3f..b52195578 100644 --- a/network/mhfpacket/msg_mhf_read_last_week_beat_ranking.go +++ b/network/mhfpacket/msg_mhf_read_last_week_beat_ranking.go @@ -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" ) // MsgMhfReadLastWeekBeatRanking represents the MSG_MHF_READ_LAST_WEEK_BEAT_RANKING -type MsgMhfReadLastWeekBeatRanking struct{} +type MsgMhfReadLastWeekBeatRanking struct { + AckHandle uint32 + Unk0 uint32 + Unk1 int32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfReadLastWeekBeatRanking) Opcode() network.PacketID { @@ -18,7 +22,10 @@ func (m *MsgMhfReadLastWeekBeatRanking) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfReadLastWeekBeatRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadInt32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_savedata.go b/network/mhfpacket/msg_mhf_savedata.go index e0fca29c5..cf41416f3 100644 --- a/network/mhfpacket/msg_mhf_savedata.go +++ b/network/mhfpacket/msg_mhf_savedata.go @@ -1,11 +1,12 @@ package mhfpacket -import ( - "errors" +import ( + "errors" + _config "erupe-ce/config" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfSavedata represents the MSG_MHF_SAVEDATA @@ -29,7 +30,9 @@ func (m *MsgMhfSavedata) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCon m.AllocMemSize = bf.ReadUint32() m.SaveType = bf.ReadUint8() m.Unk1 = bf.ReadUint32() - m.DataSize = bf.ReadUint32() + if _config.ErupeConfig.RealClientMode >= _config.G1 { + m.DataSize = bf.ReadUint32() + } if m.DataSize == 0 { // seems to be used when DataSize = 0 rather than on savetype? m.RawDataPayload = bf.ReadBytes(uint(m.AllocMemSize)) } else { diff --git a/network/mhfpacket/msg_mhf_set_ca_achievement_hist.go b/network/mhfpacket/msg_mhf_set_ca_achievement_hist.go index a04d6b89f..0b4fad343 100644 --- a/network/mhfpacket/msg_mhf_set_ca_achievement_hist.go +++ b/network/mhfpacket/msg_mhf_set_ca_achievement_hist.go @@ -1,18 +1,24 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) -// MsgMhfSetCaAchievementHist represents the MSG_MHF_SET_CA_ACHIEVEMENT_HIST -type MsgMhfSetCaAchievementHist struct{ - AckHandle uint32 +type CaAchievementHist struct { Unk0 uint32 - Unk1 uint32 + Unk1 uint8 +} + +// MsgMhfSetCaAchievementHist represents the MSG_MHF_SET_CA_ACHIEVEMENT_HIST +type MsgMhfSetCaAchievementHist struct { + AckHandle uint32 + Unk0 uint16 + Unk1 uint8 + Unk2 []CaAchievementHist } // Opcode returns the ID associated with this packet type. @@ -23,8 +29,14 @@ func (m *MsgMhfSetCaAchievementHist) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSetCaAchievementHist) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() - m.Unk1 = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint8() + for i := 0; i < int(m.Unk1); i++ { + var temp CaAchievementHist + temp.Unk0 = bf.ReadUint32() + temp.Unk1 = bf.ReadUint8() + m.Unk2 = append(m.Unk2, temp) + } return nil } diff --git a/network/mhfpacket/msg_mhf_sex_changer.go b/network/mhfpacket/msg_mhf_sex_changer.go index 74186d84b..a8754feca 100644 --- a/network/mhfpacket/msg_mhf_sex_changer.go +++ b/network/mhfpacket/msg_mhf_sex_changer.go @@ -1,17 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfSexChanger represents the MSG_MHF_SEX_CHANGER type MsgMhfSexChanger struct { AckHandle uint32 Gender uint8 + Unk0 uint8 + Unk1 uint8 + Unk2 uint8 } // Opcode returns the ID associated with this packet type. @@ -23,6 +26,9 @@ func (m *MsgMhfSexChanger) Opcode() network.PacketID { func (m *MsgMhfSexChanger) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Gender = bf.ReadUint8() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.Unk2 = bf.ReadUint8() return nil } diff --git a/network/mhfpacket/msg_mhf_stampcard_stamp.go b/network/mhfpacket/msg_mhf_stampcard_stamp.go index 8d18ae971..5ac650ad2 100644 --- a/network/mhfpacket/msg_mhf_stampcard_stamp.go +++ b/network/mhfpacket/msg_mhf_stampcard_stamp.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + _config "erupe-ce/config" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -34,12 +35,14 @@ func (m *MsgMhfStampcardStamp) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.GR = bf.ReadUint16() m.Stamps = bf.ReadUint16() _ = bf.ReadUint16() - m.Reward1 = uint16(bf.ReadUint32()) - m.Reward2 = uint16(bf.ReadUint32()) - m.Item1 = uint16(bf.ReadUint32()) - m.Item2 = uint16(bf.ReadUint32()) - m.Quantity1 = uint16(bf.ReadUint32()) - m.Quantity2 = uint16(bf.ReadUint32()) + if _config.ErupeConfig.RealClientMode > _config.Z1 { + m.Reward1 = uint16(bf.ReadUint32()) + m.Reward2 = uint16(bf.ReadUint32()) + m.Item1 = uint16(bf.ReadUint32()) + m.Item2 = uint16(bf.ReadUint32()) + m.Quantity1 = uint16(bf.ReadUint32()) + m.Quantity2 = uint16(bf.ReadUint32()) + } return nil } diff --git a/network/mhfpacket/msg_mhf_state_campaign.go b/network/mhfpacket/msg_mhf_state_campaign.go index 35cca070d..ab6342c55 100644 --- a/network/mhfpacket/msg_mhf_state_campaign.go +++ b/network/mhfpacket/msg_mhf_state_campaign.go @@ -1,18 +1,18 @@ package mhfpacket import ( + "errors" "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" ) // MsgMhfStateCampaign represents the MSG_MHF_STATE_CAMPAIGN type MsgMhfStateCampaign struct { - AckHandle uint32 - Unk0 uint8 - Unk1 uint8 - Unk2 uint16 + AckHandle uint32 + CampaignID uint32 + Unk1 uint16 } // Opcode returns the ID associated with this packet type. @@ -23,17 +23,12 @@ func (m *MsgMhfStateCampaign) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfStateCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() + m.CampaignID = bf.ReadUint32() + m.Unk1 = bf.ReadUint16() return nil } // Build builds a binary packet from the current data. func (m *MsgMhfStateCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint8(m.Unk0) - bf.WriteUint8(m.Unk1) - bf.WriteUint16(m.Unk2) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_update_beat_level.go b/network/mhfpacket/msg_mhf_update_beat_level.go index 84f41ae61..e00d50c93 100644 --- a/network/mhfpacket/msg_mhf_update_beat_level.go +++ b/network/mhfpacket/msg_mhf_update_beat_level.go @@ -1,45 +1,42 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/common/byteframe" - "erupe-ce/network" - "erupe-ce/network/clientctx" + "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfUpdateBeatLevel represents the MSG_MHF_UPDATE_BEAT_LEVEL type MsgMhfUpdateBeatLevel struct { - AckHandle uint32 - Unk1 uint32 - Unk2 uint32 - MonsterData []byte - Unk3 uint8 - Unk4 uint32 - Unk5 uint16 - Unk6 uint8 - + AckHandle uint32 + Unk1 uint32 + Unk2 uint32 + Data1 []int32 + Data2 []int32 } // Opcode returns the ID associated with this packet type. func (m *MsgMhfUpdateBeatLevel) Opcode() network.PacketID { - return network.MSG_MHF_UPDATE_BEAT_LEVEL + return network.MSG_MHF_UPDATE_BEAT_LEVEL } // Parse parses the packet from binary func (m *MsgMhfUpdateBeatLevel) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.Unk1 = bf.ReadUint32() - m.Unk2 = bf.ReadUint32() - m.MonsterData = bf.ReadBytes(uint(120)) - m.Unk3 = bf.ReadUint8() - m.Unk4 = bf.ReadUint32() - m.Unk5 = bf.ReadUint16() - m.Unk6 = bf.ReadUint8() - return nil + m.AckHandle = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint32() + for i := 0; i < 16; i++ { + m.Data1 = append(m.Data1, bf.ReadInt32()) + } + for i := 0; i < 16; i++ { + m.Data2 = append(m.Data2, bf.ReadInt32()) + } + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfUpdateBeatLevel) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_sys_create_acquire_semaphore.go b/network/mhfpacket/msg_sys_create_acquire_semaphore.go index 9f014ced7..65ec3580d 100644 --- a/network/mhfpacket/msg_sys_create_acquire_semaphore.go +++ b/network/mhfpacket/msg_sys_create_acquire_semaphore.go @@ -2,10 +2,9 @@ package mhfpacket import ( "errors" - "fmt" - - "erupe-ce/common/byteframe" "erupe-ce/common/bfutil" + "erupe-ce/common/byteframe" + _config "erupe-ce/config" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -27,8 +26,9 @@ func (m *MsgSysCreateAcquireSemaphore) Opcode() network.PacketID { func (m *MsgSysCreateAcquireSemaphore) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint16() - m.PlayerCount = bf.ReadUint8() - fmt.Printf("PLAYER COUNT :: %d", m.PlayerCount) + if _config.ErupeConfig.RealClientMode >= _config.G1 { + m.PlayerCount = bf.ReadUint8() + } SemaphoreIDLength := bf.ReadUint8() m.SemaphoreID = string(bfutil.UpToNull(bf.ReadBytes(uint(SemaphoreIDLength)))) return nil diff --git a/network/mhfpacket/msg_sys_terminal_log.go b/network/mhfpacket/msg_sys_terminal_log.go index 536d35f18..079ba5bd6 100644 --- a/network/mhfpacket/msg_sys_terminal_log.go +++ b/network/mhfpacket/msg_sys_terminal_log.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + _config "erupe-ce/config" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -37,12 +38,16 @@ func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client m.EntryCount = bf.ReadUint16() m.Unk0 = bf.ReadUint16() + values := 15 + if _config.ErupeConfig.RealClientMode <= _config.F5 { + values = 7 + } for i := 0; i < int(m.EntryCount); i++ { e := &TerminalLogEntry{} e.Index = bf.ReadUint32() e.Type1 = bf.ReadUint8() e.Type2 = bf.ReadUint8() - for j := 0; j < 15; j++ { + for j := 0; j < values; j++ { e.Data = append(e.Data, bf.ReadInt16()) } m.Entries = append(m.Entries, e) diff --git a/patch-schema/tower.sql b/patch-schema/tower.sql new file mode 100644 index 000000000..0697fc2be --- /dev/null +++ b/patch-schema/tower.sql @@ -0,0 +1,29 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS tower ( + char_id INT, + tr INT, + trp INT, + tsp INT, + block1 INT, + block2 INT, + skills TEXT DEFAULT '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0', + gems TEXT DEFAULT '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0' +); + +ALTER TABLE IF EXISTS guild_characters + ADD COLUMN IF NOT EXISTS tower_mission_1 INT; + +ALTER TABLE IF EXISTS guild_characters + ADD COLUMN IF NOT EXISTS tower_mission_2 INT; + +ALTER TABLE IF EXISTS guild_characters + ADD COLUMN IF NOT EXISTS tower_mission_3 INT; + +ALTER TABLE IF EXISTS guilds + ADD COLUMN IF NOT EXISTS tower_mission_page INT DEFAULT 1; + +ALTER TABLE IF EXISTS guilds + ADD COLUMN IF NOT EXISTS tower_rp INT DEFAULT 0; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index dc285d9aa..81cd1838a 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -6,6 +6,7 @@ import ( "erupe-ce/common/mhfcourse" ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "fmt" "io" "net" @@ -27,15 +28,16 @@ func stubEnumerateNoResults(s *Session, ackHandle uint32) { doAckBufSucceed(s, ackHandle, enumBf.Data()) } -// Temporary function to just return no results for many MSG_MHF_GET* packets. -func stubGetNoResults(s *Session, ackHandle uint32) { - resp := byteframe.NewByteFrame() - resp.WriteUint32(0x0A218EAD) // Unk shared ID. Sent in response of MSG_MHF_GET_TOWER_INFO, MSG_MHF_GET_PAPER_DATA etc. (World ID?) - resp.WriteUint32(0) // Unk - resp.WriteUint32(0) // Unk - resp.WriteUint32(0) // Entry count - - doAckBufSucceed(s, ackHandle, resp.Data()) +func doAckEarthSucceed(s *Session, ackHandle uint32, data []*byteframe.ByteFrame) { + bf := byteframe.NewByteFrame() + bf.WriteUint32(uint32(s.server.erupeConfig.DevModeOptions.EarthIDOverride)) + bf.WriteUint32(0) + bf.WriteUint32(0) + bf.WriteUint32(uint32(len(data))) + for i := range data { + bf.WriteBytes(data[i].Data()) + } + doAckBufSucceed(s, ackHandle, bf.Data()) } func doAckBufSucceed(s *Session, ackHandle uint32, data []byte) { @@ -245,7 +247,7 @@ func logoutPlayer(s *Session) { removeSessionFromStage(s) saveData, err := GetCharacterSaveData(s, s.charID) - if err != nil { + if err != nil || saveData == nil { s.logger.Error("Failed to get savedata") return } @@ -446,48 +448,110 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) { } } case 4: // Find Party + type FindPartyParams struct { + StagePrefix string + RankRestriction uint16 + Targets []uint16 + Unk0 []uint16 + Unk1 []uint16 + QuestID []uint16 + } + findPartyParams := FindPartyParams{ + StagePrefix: "sl2Ls210", + } bf := byteframe.NewByteFrameFromBytes(pkt.MessageData) - setting := bf.ReadUint8() + numParams := int(bf.ReadUint8()) maxResults := bf.ReadUint16() - bf.Seek(2, 1) - partyType := bf.ReadUint16() - rankRestriction := uint16(0) - if setting >= 2 { - bf.Seek(2, 1) - rankRestriction = bf.ReadUint16() - } - targets := make([]uint16, 4) - if setting >= 3 { - bf.Seek(1, 1) - lenTargets := int(bf.ReadUint8()) - for i := 0; i < lenTargets; i++ { - targets[i] = bf.ReadUint16() + for i := 0; i < numParams; i++ { + switch bf.ReadUint8() { + case 0: + values := int(bf.ReadUint8()) + for i := 0; i < values; i++ { + if _config.ErupeConfig.RealClientMode >= _config.Z1 { + findPartyParams.RankRestriction = bf.ReadUint16() + } else { + findPartyParams.RankRestriction = uint16(bf.ReadInt8()) + } + } + case 1: + values := int(bf.ReadUint8()) + for i := 0; i < values; i++ { + if _config.ErupeConfig.RealClientMode >= _config.Z1 { + findPartyParams.Targets = append(findPartyParams.Targets, bf.ReadUint16()) + } else { + findPartyParams.Targets = append(findPartyParams.Targets, uint16(bf.ReadInt8())) + } + } + case 2: + values := int(bf.ReadUint8()) + for i := 0; i < values; i++ { + var value int16 + if _config.ErupeConfig.RealClientMode >= _config.Z1 { + value = bf.ReadInt16() + } else { + value = int16(bf.ReadInt8()) + } + switch value { + case 0: // Public Bar + findPartyParams.StagePrefix = "sl2Ls210" + case 1: // Tokotoko Partnya + findPartyParams.StagePrefix = "sl2Ls463" + case 2: // Hunting Prowess Match + findPartyParams.StagePrefix = "sl2Ls286" + case 3: // Volpakkun Together + findPartyParams.StagePrefix = "sl2Ls465" + case 5: // Quick Party + // Unk + } + } + case 3: // Unknown + values := int(bf.ReadUint8()) + for i := 0; i < values; i++ { + if _config.ErupeConfig.RealClientMode >= _config.Z1 { + findPartyParams.Unk0 = append(findPartyParams.Unk0, bf.ReadUint16()) + } else { + findPartyParams.Unk0 = append(findPartyParams.Unk0, uint16(bf.ReadInt8())) + } + } + case 4: // Looking for n or already have n + values := int(bf.ReadUint8()) + for i := 0; i < values; i++ { + if _config.ErupeConfig.RealClientMode >= _config.Z1 { + findPartyParams.Unk1 = append(findPartyParams.Unk1, bf.ReadUint16()) + } else { + findPartyParams.Unk1 = append(findPartyParams.Unk1, uint16(bf.ReadInt8())) + } + } + case 5: + values := int(bf.ReadUint8()) + for i := 0; i < values; i++ { + if _config.ErupeConfig.RealClientMode >= _config.Z1 { + findPartyParams.QuestID = append(findPartyParams.QuestID, bf.ReadUint16()) + } else { + findPartyParams.QuestID = append(findPartyParams.QuestID, uint16(bf.ReadInt8())) + } + } } } - var stagePrefix string - switch partyType { - case 0: // Public Bar - stagePrefix = "sl2Ls210" - case 1: // Tokotoko Partnya - stagePrefix = "sl2Ls463" - case 2: // Hunting Prowess Match - stagePrefix = "sl2Ls286" - case 3: // Volpakkun Together - stagePrefix = "sl2Ls465" - case 5: // Quick Party - // Unk - } for _, c := range s.server.Channels { for _, stage := range c.stages { if count == maxResults { break } - if strings.HasPrefix(stage.id, stagePrefix) { + if strings.HasPrefix(stage.id, findPartyParams.StagePrefix) { sb3 := byteframe.NewByteFrameFromBytes(stage.rawBinaryData[stageBinaryKey{1, 3}]) sb3.Seek(4, 0) stageRankRestriction := sb3.ReadUint16() stageTarget := sb3.ReadUint16() - if rankRestriction != 0xFFFF && stageRankRestriction < rankRestriction { + if stageRankRestriction > findPartyParams.RankRestriction { + continue + } + if len(findPartyParams.Targets) > 0 { + for _, target := range findPartyParams.Targets { + if target == stageTarget { + break + } + } continue } count++ @@ -551,10 +615,6 @@ func handleMsgSysInfokyserver(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetCaUniqueID(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {} - func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfTransferItem) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) @@ -1574,138 +1634,209 @@ func handleMsgMhfStampcardPrize(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfUnreserveSrg(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfReadBeatLevel) - - // This response is fixed and will never change on JP, - // but I've left it dynamic for possible other client differences. - resp := byteframe.NewByteFrame() - for i := 0; i < int(pkt.ValidIDCount); i++ { - resp.WriteUint32(pkt.IDs[i]) - resp.WriteUint32(1) - resp.WriteUint32(1) - resp.WriteUint32(1) - } - - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) -} - -func handleMsgMhfUpdateBeatLevel(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfUpdateBeatLevel) - - doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) -} - -func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadBeatLevelMyRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket) {} - func handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetEarthStatus) - - // TODO(Andoryuuta): Track down format for this data, - // it can somehow be parsed as 8*uint32 chunks if the header is right. - /* - BEFORE ack-refactor: - resp := byteframe.NewByteFrame() - resp.WriteUint32(0) - resp.WriteUint32(0) - - s.QueueAck(pkt.AckHandle, resp.Data()) - */ - doAckBufSucceed(s, pkt.AckHandle, []byte{}) + bf := byteframe.NewByteFrame() + bf.WriteUint32(uint32(TimeWeekStart().Add(time.Hour * -24).Unix())) // Start + bf.WriteUint32(uint32(TimeWeekNext().Add(time.Hour * 24).Unix())) // End + bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthStatusOverride) + bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthIDOverride) + bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthMonsterOverride) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetEarthValue(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetEarthValue) - var earthValues []struct{ Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32 } - if pkt.ReqType == 3 { - earthValues = []struct { - Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32 - }{ - // TW identical to JP - { - Unk0: 0x03E9, - Unk1: 0x24, - }, - { - Unk0: 0x2329, - Unk1: 0x03, - }, - { - Unk0: 0x232A, - Unk1: 0x0A, - Unk2: 0x012C, - }, + type EarthValues struct { + Value []uint32 + } + + var earthValues []EarthValues + switch pkt.ReqType { + case 1: + earthValues = []EarthValues{ + {[]uint32{1, 312, 0, 0, 0, 0}}, + {[]uint32{2, 99, 0, 0, 0, 0}}, } - } else if pkt.ReqType == 2 { - earthValues = []struct { - Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32 - }{ - // JP response was empty - { - Unk0: 0x01, - Unk1: 0x168B, - }, - { - Unk0: 0x02, - Unk1: 0x0737, - }, + case 2: + earthValues = []EarthValues{ + {[]uint32{1, 5771, 0, 0, 0, 0}}, + {[]uint32{2, 1847, 0, 0, 0, 0}}, } - } else if pkt.ReqType == 1 { - earthValues = []struct { - Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32 - }{ - // JP simply sent 01 and 02 respectively - { - Unk0: 0x01, - Unk1: 0x0138, - }, - { - Unk0: 0x02, - Unk1: 0x63, - }, + case 3: + earthValues = []EarthValues{ + {[]uint32{1001, 36, 0, 0, 0, 0}}, + {[]uint32{9001, 3, 0, 0, 0, 0}}, + {[]uint32{9002, 10, 300, 0, 0, 0}}, } } - resp := byteframe.NewByteFrame() - resp.WriteUint32(0x0A218EAD) // Unk shared ID. Sent in response of MSG_MHF_GET_TOWER_INFO, MSG_MHF_GET_PAPER_DATA etc. - resp.WriteUint32(0) // Unk - resp.WriteUint32(0) // Unk - resp.WriteUint32(uint32(len(earthValues))) // value count - for _, v := range earthValues { - resp.WriteUint32(v.Unk0) - resp.WriteUint32(v.Unk1) - resp.WriteUint32(v.Unk2) - resp.WriteUint32(v.Unk3) - resp.WriteUint32(v.Unk4) - resp.WriteUint32(v.Unk5) + var data []*byteframe.ByteFrame + for _, i := range earthValues { + bf := byteframe.NewByteFrame() + for _, j := range i.Value { + bf.WriteUint32(j) + } + data = append(data, bf) } - - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + doAckEarthSucceed(s, pkt.AckHandle, data) } func handleMsgMhfDebugPostValue(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgMhfGetNotice(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) {} - func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetSenyuDailyCount) + bf := byteframe.NewByteFrame() + bf.WriteUint16(0) + bf.WriteUint16(0) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} + +type SeibattleTimetable struct { + Start time.Time + End time.Time +} + +type SeibattleKeyScore struct { + Unk0 uint8 + Unk1 int32 +} + +type SeibattleCareer struct { + Unk0 uint16 + Unk1 uint16 + Unk2 uint16 +} + +type SeibattleOpponent struct { + Unk0 int32 + Unk1 int8 +} + +type SeibattleConventionResult struct { + Unk0 uint32 + Unk1 uint16 + Unk2 uint16 + Unk3 uint16 + Unk4 uint16 +} + +type SeibattleCharScore struct { + Unk0 uint32 +} + +type SeibattleCurResult struct { + Unk0 uint32 + Unk1 uint16 + Unk2 uint16 + Unk3 uint16 +} + +type Seibattle struct { + Timetable []SeibattleTimetable + KeyScore []SeibattleKeyScore + Career []SeibattleCareer + Opponent []SeibattleOpponent + ConventionResult []SeibattleConventionResult + CharScore []SeibattleCharScore + CurResult []SeibattleCurResult +} func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetSeibattle) - stubGetNoResults(s, pkt.AckHandle) + var data []*byteframe.ByteFrame + seibattle := Seibattle{ + Timetable: []SeibattleTimetable{ + {TimeMidnight(), TimeMidnight().Add(time.Hour * 8)}, + {TimeMidnight().Add(time.Hour * 8), TimeMidnight().Add(time.Hour * 16)}, + {TimeMidnight().Add(time.Hour * 16), TimeMidnight().Add(time.Hour * 24)}, + }, + KeyScore: []SeibattleKeyScore{ + {0, 0}, + }, + Career: []SeibattleCareer{ + {0, 0, 0}, + }, + Opponent: []SeibattleOpponent{ + {1, 1}, + }, + ConventionResult: []SeibattleConventionResult{ + {0, 0, 0, 0, 0}, + }, + CharScore: []SeibattleCharScore{ + {0}, + }, + CurResult: []SeibattleCurResult{ + {0, 0, 0, 0}, + }, + } + + switch pkt.Type { + case 1: + for _, timetable := range seibattle.Timetable { + bf := byteframe.NewByteFrame() + bf.WriteUint32(uint32(timetable.Start.Unix())) + bf.WriteUint32(uint32(timetable.End.Unix())) + data = append(data, bf) + } + case 3: // Key score? + for _, keyScore := range seibattle.KeyScore { + bf := byteframe.NewByteFrame() + bf.WriteUint8(keyScore.Unk0) + bf.WriteInt32(keyScore.Unk1) + data = append(data, bf) + } + case 4: // Career? + for _, career := range seibattle.Career { + bf := byteframe.NewByteFrame() + bf.WriteUint16(career.Unk0) + bf.WriteUint16(career.Unk1) + bf.WriteUint16(career.Unk2) + data = append(data, bf) + } + case 5: // Opponent? + for _, opponent := range seibattle.Opponent { + bf := byteframe.NewByteFrame() + bf.WriteInt32(opponent.Unk0) + bf.WriteInt8(opponent.Unk1) + data = append(data, bf) + } + case 6: // Convention result? + for _, conventionResult := range seibattle.ConventionResult { + bf := byteframe.NewByteFrame() + bf.WriteUint32(conventionResult.Unk0) + bf.WriteUint16(conventionResult.Unk1) + bf.WriteUint16(conventionResult.Unk2) + bf.WriteUint16(conventionResult.Unk3) + bf.WriteUint16(conventionResult.Unk4) + data = append(data, bf) + } + case 7: // Char score? + for _, charScore := range seibattle.CharScore { + bf := byteframe.NewByteFrame() + bf.WriteUint32(charScore.Unk0) + data = append(data, bf) + } + case 8: // Cur result? + for _, curResult := range seibattle.CurResult { + bf := byteframe.NewByteFrame() + bf.WriteUint32(curResult.Unk0) + bf.WriteUint16(curResult.Unk1) + bf.WriteUint16(curResult.Unk2) + bf.WriteUint16(curResult.Unk3) + data = append(data, bf) + } + } + doAckEarthSucceed(s, pkt.AckHandle, data) } func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go index 46a6425a0..67b7c3807 100644 --- a/server/channelserver/handlers_cafe.go +++ b/server/channelserver/handlers_cafe.go @@ -270,6 +270,12 @@ func handleMsgMhfPostBoostTimeQuestReturn(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } -func handleMsgMhfPostBoostTime(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfPostBoostTime(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfPostBoostTime) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} -func handleMsgMhfPostBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfPostBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfPostBoostTimeLimit) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} diff --git a/server/channelserver/handlers_campaign.go b/server/channelserver/handlers_campaign.go index 8522adab2..2041b484b 100644 --- a/server/channelserver/handlers_campaign.go +++ b/server/channelserver/handlers_campaign.go @@ -1,18 +1,173 @@ package channelserver -import "erupe-ce/network/mhfpacket" +import ( + "erupe-ce/common/byteframe" + ps "erupe-ce/common/pascalstring" + "erupe-ce/common/stringsupport" + "erupe-ce/network/mhfpacket" + "time" +) + +type CampaignEvent struct { + ID uint32 + Unk0 uint32 + MinHR int16 + MaxHR int16 + MinSR int16 + MaxSR int16 + MinGR int16 + MaxGR int16 + Unk1 uint16 + Unk2 uint8 + Unk3 uint8 + Unk4 uint16 + Unk5 uint16 + Start time.Time + End time.Time + Unk6 uint8 + String0 string + String1 string + String2 string + String3 string + Link string + Prefix string + Categories []uint16 +} + +type CampaignCategory struct { + ID uint16 + Type uint8 + Title string + Description string +} + +type CampaignLink struct { + CategoryID uint16 + CampaignID uint32 +} func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateCampaign) - doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + bf := byteframe.NewByteFrame() + + events := []CampaignEvent{} + categories := []CampaignCategory{} + var campaignLinks []CampaignLink + + if len(events) > 255 { + bf.WriteUint8(255) + bf.WriteUint16(uint16(len(events))) + } else { + bf.WriteUint8(uint8(len(events))) + } + for _, event := range events { + bf.WriteUint32(event.ID) + bf.WriteUint32(event.Unk0) + bf.WriteInt16(event.MinHR) + bf.WriteInt16(event.MaxHR) + bf.WriteInt16(event.MinSR) + bf.WriteInt16(event.MaxSR) + bf.WriteInt16(event.MinGR) + bf.WriteInt16(event.MaxGR) + bf.WriteUint16(event.Unk1) + bf.WriteUint8(event.Unk2) + bf.WriteUint8(event.Unk3) + bf.WriteUint16(event.Unk4) + bf.WriteUint16(event.Unk5) + bf.WriteUint32(uint32(event.Start.Unix())) + bf.WriteUint32(uint32(event.End.Unix())) + bf.WriteUint8(event.Unk6) + ps.Uint8(bf, event.String0, true) + ps.Uint8(bf, event.String1, true) + ps.Uint8(bf, event.String2, true) + ps.Uint8(bf, event.String3, true) + ps.Uint8(bf, event.Link, true) + for i := range event.Categories { + campaignLinks = append(campaignLinks, CampaignLink{event.Categories[i], event.ID}) + } + } + + if len(events) > 255 { + bf.WriteUint8(255) + bf.WriteUint16(uint16(len(events))) + } else { + bf.WriteUint8(uint8(len(events))) + } + for _, event := range events { + bf.WriteUint32(event.ID) + bf.WriteUint8(1) // Always 1? + bf.WriteBytes([]byte(event.Prefix)) + } + + if len(categories) > 255 { + bf.WriteUint8(255) + bf.WriteUint16(uint16(len(categories))) + } else { + bf.WriteUint8(uint8(len(categories))) + } + for _, category := range categories { + bf.WriteUint16(category.ID) + bf.WriteUint8(category.Type) + xTitle := stringsupport.UTF8ToSJIS(category.Title) + xDescription := stringsupport.UTF8ToSJIS(category.Description) + bf.WriteUint8(uint8(len(xTitle))) + bf.WriteUint8(uint8(len(xDescription))) + bf.WriteBytes(xTitle) + bf.WriteBytes(xDescription) + } + + if len(campaignLinks) > 255 { + bf.WriteUint8(255) + bf.WriteUint16(uint16(len(campaignLinks))) + } else { + bf.WriteUint8(uint8(len(campaignLinks))) + } + for _, link := range campaignLinks { + bf.WriteUint16(link.CategoryID) + bf.WriteUint32(link.CampaignID) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfStateCampaign) - doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + bf := byteframe.NewByteFrame() + bf.WriteUint16(1) + bf.WriteUint16(0) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfApplyCampaign) - doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + bf := byteframe.NewByteFrame() + bf.WriteUint32(1) + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) +} + +func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateItem) + items := []struct { + Unk0 uint32 + Unk1 uint16 + Unk2 uint16 + Unk3 uint16 + Unk4 uint32 + Unk5 uint32 + }{} + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(len(items))) + for _, item := range items { + bf.WriteUint32(item.Unk0) + bf.WriteUint16(item.Unk1) + bf.WriteUint16(item.Unk2) + bf.WriteUint16(item.Unk3) + bf.WriteUint32(item.Unk4) + bf.WriteUint32(item.Unk5) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} + +func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfAcquireItem) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/server/channelserver/handlers_caravan.go b/server/channelserver/handlers_caravan.go index 86cf73249..c90f44812 100644 --- a/server/channelserver/handlers_caravan.go +++ b/server/channelserver/handlers_caravan.go @@ -1,21 +1,73 @@ package channelserver import ( - "encoding/hex" + "erupe-ce/common/byteframe" + "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" + "time" ) +type RyoudamaReward struct { + Unk0 uint8 + Unk1 uint8 + Unk2 uint16 + Unk3 uint16 + Unk4 uint16 + Unk5 uint16 +} + +type RyoudamaKeyScore struct { + Unk0 uint8 + Unk1 int32 +} + +type RyoudamaCharInfo struct { + CID uint32 + Unk0 int32 + Name string +} + +type RyoudamaBoostInfo struct { + Start time.Time + End time.Time +} + +type Ryoudama struct { + Reward []RyoudamaReward + KeyScore []RyoudamaKeyScore + CharInfo []RyoudamaCharInfo + BoostInfo []RyoudamaBoostInfo + Score []int32 +} + func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetRyoudama) - // likely guild related - // REQ: 00 04 13 53 8F 18 00 - // RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 01 FE 4E - // REQ: 00 06 13 53 8F 18 00 - // RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 - // REQ: 00 05 13 53 8F 18 00 - // RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 0E 2A 15 9E CC 00 00 00 01 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 1E 55 B0 2F 00 00 00 01 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 2A 15 9E CC 00 00 00 02 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 03 D5 30 56 00 00 00 02 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 3F 57 76 9F 00 00 00 03 93 56 92 6E 96 B3 97 70 00 00 00 00 00 00 38 D9 0E C4 00 00 00 03 87 64 83 78 83 42 00 00 00 00 00 00 00 00 23 F3 B9 77 00 00 00 04 82 B3 82 CC 82 DC 82 E9 81 99 00 00 00 00 3F 1B 17 9C 00 00 00 04 82 B1 82 A4 82 BD 00 00 00 00 00 00 00 00 00 B9 F9 C0 00 00 00 05 82 CD 82 E9 82 A9 00 00 00 00 00 00 00 00 23 9F 9A EA 00 00 00 05 83 70 83 62 83 4C 83 83 83 49 00 00 00 00 38 D9 0E C4 00 00 00 06 87 64 83 78 83 42 00 00 00 00 00 00 00 00 1E 55 B0 2F 00 00 00 06 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 03 D5 30 56 00 00 00 07 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 02 D3 B8 77 00 00 00 07 6F 77 6C 32 35 32 35 00 00 00 00 00 00 00 - data, _ := hex.DecodeString("0A218EAD0000000000000000000000010000000000000000") - doAckBufSucceed(s, pkt.AckHandle, data) + var data []*byteframe.ByteFrame + ryoudama := Ryoudama{Score: []int32{0}} + switch pkt.Request2 { + case 4: + for _, score := range ryoudama.Score { + bf := byteframe.NewByteFrame() + bf.WriteInt32(score) + data = append(data, bf) + } + case 5: + for _, info := range ryoudama.CharInfo { + bf := byteframe.NewByteFrame() + bf.WriteUint32(info.CID) + bf.WriteInt32(info.Unk0) + bf.WriteBytes(stringsupport.PaddedString(info.Name, 14, true)) + data = append(data, bf) + } + case 6: + for _, info := range ryoudama.BoostInfo { + bf := byteframe.NewByteFrame() + bf.WriteUint32(uint32(info.Start.Unix())) + bf.WriteUint32(uint32(info.End.Unix())) + data = append(data, bf) + } + } + doAckEarthSucceed(s, pkt.AckHandle, data) } func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {} @@ -31,8 +83,41 @@ func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } -func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfCaravanMyScore) + var data []*byteframe.ByteFrame + /* + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + */ + doAckEarthSucceed(s, pkt.AckHandle, data) +} -func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfCaravanRanking) + var data []*byteframe.ByteFrame + /* RYOUDAN + bf.WriteInt32(1) + bf.WriteUint32(2) + bf.WriteBytes(stringsupport.PaddedString("Test", 26, true)) + */ -func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) {} + /* PERSONAL + bf.WriteInt32(1) + bf.WriteBytes(stringsupport.PaddedString("Test", 14, true)) + */ + doAckEarthSucceed(s, pkt.AckHandle, data) +} + +func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfCaravanMyRank) + var data []*byteframe.ByteFrame + /* + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + */ + doAckEarthSucceed(s, pkt.AckHandle, data) +} diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 7c961b5e9..3e950657f 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -35,16 +35,16 @@ const ( BroadcastTypeWorld = 0x0a ) -var commands map[string]config.Command +var commands map[string]_config.Command func init() { - commands = make(map[string]config.Command) + commands = make(map[string]_config.Command) zapConfig := zap.NewDevelopmentConfig() zapConfig.DisableCaller = true zapLogger, _ := zapConfig.Build() defer zapLogger.Sync() logger := zapLogger.Named("commands") - cmds := config.ErupeConfig.Commands + cmds := _config.ErupeConfig.Commands for _, cmd := range cmds { commands[cmd.Name] = cmd if cmd.Enabled { @@ -55,7 +55,7 @@ func init() { } } -func sendDisabledCommandMessage(s *Session, cmd config.Command) { +func sendDisabledCommandMessage(s *Session, cmd _config.Command) { sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandDisabled"], cmd.Name)) } @@ -211,7 +211,7 @@ func parseChatCommand(s *Session, command string) { for _, course := range mhfcourse.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 slices.Contains(s.server.erupeConfig.Courses, _config.Course{Name: course.Aliases()[0], Enabled: true}) { var delta, rightsInt uint32 if mhfcourse.CourseExists(course.ID, s.courses) { ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool { diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 165580fe7..bdbd2f744 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -5,33 +5,36 @@ import ( "errors" "erupe-ce/common/bfutil" "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "erupe-ce/network/mhfpacket" "erupe-ce/server/channelserver/compression/nullcomp" "go.uber.org/zap" ) +type SavePointer int + const ( - pointerGender = 0x51 // +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 + pGender = iota // +1 + pRP // +2 + pHouseTier // +5 + pHouseData // +195 + pBookshelfData // +5576 + pGalleryData // +1748 + pToreData // +240 + pGardenData // +68 + pWeaponType // +1 + pWeaponID // +2 + pHRP // +2 + pGRP // +4 + pKQF // +8 ) type CharacterSaveData struct { CharID uint32 Name string IsNewCharacter bool + Pointers map[SavePointer]int Gender bool RP uint16 @@ -51,6 +54,39 @@ type CharacterSaveData struct { decompSave []byte } +func getPointers() map[SavePointer]int { + pointers := map[SavePointer]int{pGender: 81} + switch _config.ErupeConfig.RealClientMode { + case _config.ZZ: + pointers[pWeaponID] = 128522 + pointers[pWeaponType] = 128789 + pointers[pHouseTier] = 129900 + pointers[pToreData] = 130228 + pointers[pHRP] = 130550 + pointers[pGRP] = 130556 + pointers[pHouseData] = 130561 + pointers[pBookshelfData] = 139928 + pointers[pGalleryData] = 140064 + pointers[pGardenData] = 142424 + pointers[pRP] = 142614 + pointers[pKQF] = 146720 + case _config.Z2, _config.Z1, _config.G101, _config.G10: + pointers[pWeaponID] = 92522 + pointers[pWeaponType] = 92789 + pointers[pHouseTier] = 93900 + pointers[pToreData] = 94228 + pointers[pHRP] = 94550 + pointers[pGRP] = 94556 + pointers[pHouseData] = 94561 + pointers[pBookshelfData] = 103928 + pointers[pGalleryData] = 104064 + pointers[pGardenData] = 106424 + pointers[pRP] = 106614 + pointers[pKQF] = 110720 + } + return pointers +} + 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 { @@ -64,7 +100,9 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) return nil, err } - saveData := &CharacterSaveData{} + saveData := &CharacterSaveData{ + Pointers: getPointers(), + } err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name) if err != nil { s.logger.Error("Failed to scan savedata", zap.Error(err), zap.Uint32("charID", charID)) @@ -95,13 +133,18 @@ func (save *CharacterSaveData) Save(s *Session) { save.updateSaveDataWithStruct() - err := save.Compress() - if err != nil { - s.logger.Error("Failed to compress savedata", zap.Error(err)) - return + if _config.ErupeConfig.RealClientMode >= _config.G1 { + err := save.Compress() + if err != nil { + s.logger.Error("Failed to compress savedata", zap.Error(err)) + return + } + } else { + // Saves were not compressed + save.compSave = save.decompSave } - _, 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 + _, 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)) @@ -133,38 +176,42 @@ func (save *CharacterSaveData) Decompress() error { func (save *CharacterSaveData) updateSaveDataWithStruct() { rpBytes := make([]byte, 2) binary.LittleEndian.PutUint16(rpBytes, save.RP) - copy(save.decompSave[pointerRP:pointerRP+2], rpBytes) - copy(save.decompSave[pointerKQF:pointerKQF+8], save.KQF) + if _config.ErupeConfig.RealClientMode >= _config.G10 { + copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) + copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF) + } } // This will update the save struct with the values stored in the character save func (save *CharacterSaveData) updateStructWithSaveData() { save.Name = stringsupport.SJISToUTF8(bfutil.UpToNull(save.decompSave[88:100])) - if save.decompSave[pointerGender] == 1 { + if save.decompSave[save.Pointers[pGender]] == 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])) + if _config.ErupeConfig.RealClientMode >= _config.G10 { + save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) + save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] + save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] + save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+5576] + save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748] + save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240] + save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68] + save.WeaponType = save.decompSave[save.Pointers[pWeaponType]] + save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2]) + save.HRP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHRP] : save.Pointers[pHRP]+2]) + if save.HRP == uint16(999) { + save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) + } + save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] } - save.KQF = save.decompSave[pointerKQF : pointerKQF+8] } return } func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSexChanger) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 64b14072c..bf8ed7a29 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -1,12 +1,12 @@ package channelserver import ( - "encoding/hex" "erupe-ce/common/stringsupport" "fmt" "io" "os" "path/filepath" + "time" "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" @@ -310,43 +310,1373 @@ func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } +var paperGiftData = map[uint32][]PaperGift{ + 6001: { + {11159, 1, 1, 5000}, + {11160, 1, 1, 3350}, + {11161, 1, 1, 1500}, + {11162, 1, 1, 100}, + {11163, 1, 1, 50}, + }, + 6002: { + {11159, 2, 1, 1800}, + {11160, 2, 1, 1200}, + {11161, 2, 1, 500}, + {11162, 1, 1, 50}, + {11037, 1, 1, 150}, + {11038, 1, 1, 150}, + {11044, 1, 1, 150}, + {11057, 1, 1, 150}, + {11059, 1, 1, 150}, + {11079, 1, 1, 150}, + {11098, 1, 1, 150}, + {11104, 1, 1, 150}, + {11117, 1, 1, 150}, + {11128, 1, 1, 150}, + {11133, 1, 1, 150}, + {11137, 1, 1, 150}, + {11143, 1, 1, 150}, + {11132, 1, 1, 150}, + {11039, 1, 1, 150}, + {11040, 1, 1, 150}, + {11049, 1, 1, 150}, + {11061, 1, 1, 150}, + {11063, 1, 1, 150}, + {11077, 1, 1, 150}, + {11099, 1, 1, 150}, + {11105, 1, 1, 150}, + {11129, 1, 1, 150}, + {11130, 1, 1, 150}, + {11131, 1, 1, 150}, + {11139, 1, 1, 150}, + {11145, 1, 1, 150}, + {11096, 1, 1, 150}, + {11041, 1, 1, 150}, + {11047, 1, 1, 150}, + {11054, 1, 1, 150}, + {11065, 1, 1, 150}, + {11068, 1, 1, 150}, + {11075, 1, 1, 150}, + {11100, 1, 1, 150}, + {11106, 1, 1, 150}, + {11119, 1, 1, 150}, + {11135, 1, 1, 150}, + {11136, 1, 1, 150}, + {11138, 1, 1, 150}, + {11088, 1, 1, 150}, + {10370, 1, 1, 150}, + {10368, 1, 1, 150}, + }, + 6010: { + {11159, 1, 1, 3700}, + {11160, 1, 1, 2900}, + {11161, 1, 1, 1300}, + {11453, 1, 1, 250}, + {11454, 1, 1, 250}, + {12055, 1, 1, 250}, + {12065, 1, 1, 250}, + {12058, 1, 1, 250}, + {12068, 1, 1, 250}, + {11774, 1, 1, 200}, + {11773, 1, 1, 400}, + }, + 6011: { + {11159, 1, 1, 3700}, + {11160, 1, 1, 2900}, + {11161, 1, 1, 1300}, + {11453, 1, 1, 250}, + {11454, 1, 1, 250}, + {12055, 1, 1, 250}, + {12065, 1, 1, 250}, + {12058, 1, 1, 250}, + {12068, 1, 1, 250}, + {11774, 1, 1, 200}, + {11773, 1, 1, 400}, + }, + 6012: { + {11159, 2, 1, 3500}, + {11160, 2, 1, 2900}, + {11161, 2, 1, 1300}, + {12508, 1, 1, 400}, + {11453, 1, 1, 200}, + {11454, 1, 1, 200}, + {12055, 1, 1, 200}, + {12065, 1, 1, 200}, + {12058, 1, 1, 200}, + {12068, 1, 1, 200}, + {11775, 1, 1, 400}, + {11776, 1, 1, 200}, + {11777, 1, 1, 100}, + }, + 7001: { + {11037, 1, 1, 290}, + {11038, 1, 1, 270}, + {11044, 1, 1, 270}, + {11057, 1, 1, 290}, + {11059, 1, 1, 290}, + {11079, 1, 1, 290}, + {11098, 1, 1, 280}, + {11104, 1, 1, 300}, + {11117, 1, 1, 280}, + {11128, 1, 1, 290}, + {11133, 1, 1, 290}, + {11137, 1, 1, 300}, + {11143, 1, 1, 290}, + {11132, 1, 1, 270}, + {11042, 1, 1, 47}, + {11045, 1, 1, 47}, + {11064, 1, 1, 47}, + {11062, 1, 1, 47}, + {11070, 1, 1, 48}, + {11101, 1, 1, 47}, + {11108, 1, 1, 47}, + {11109, 1, 1, 47}, + {11120, 1, 1, 47}, + {11122, 1, 1, 47}, + {11134, 1, 1, 47}, + {11141, 1, 1, 47}, + {11084, 1, 1, 47}, + {11087, 1, 1, 47}, + {11094, 1, 1, 47}, + {10374, 1, 1, 47}, + {10375, 1, 1, 47}, + {11051, 1, 1, 17}, + {11071, 1, 1, 16}, + {11076, 1, 1, 16}, + {11102, 1, 1, 17}, + {11124, 1, 1, 17}, + {11090, 1, 1, 17}, + {11159, 1, 1, 1200}, + {11159, 2, 1, 650}, + {11160, 1, 1, 800}, + {11160, 2, 1, 300}, + {11161, 1, 1, 100}, + {11161, 2, 1, 50}, + {11164, 1, 1, 100}, + {11162, 1, 1, 100}, + {11163, 1, 1, 100}, + {11158, 1, 1, 300}, + {11463, 1, 1, 300}, + {11356, 1, 1, 300}, + {11464, 1, 1, 300}, + {11357, 1, 1, 500}, + {11039, 1, 2, 300}, + {11040, 1, 2, 270}, + {11049, 1, 2, 300}, + {11061, 1, 2, 290}, + {11063, 1, 2, 290}, + {11077, 1, 2, 290}, + {11099, 1, 2, 280}, + {11105, 1, 2, 300}, + {11129, 1, 2, 250}, + {11130, 1, 2, 300}, + {11131, 1, 2, 280}, + {11139, 1, 2, 290}, + {11145, 1, 2, 260}, + {11096, 1, 2, 300}, + {11046, 1, 2, 47}, + {11066, 1, 2, 47}, + {11067, 1, 2, 47}, + {11072, 1, 2, 47}, + {11082, 1, 2, 47}, + {11103, 1, 2, 47}, + {11110, 1, 2, 47}, + {11112, 1, 2, 47}, + {11114, 1, 2, 47}, + {11115, 1, 2, 47}, + {11121, 1, 2, 47}, + {11144, 1, 2, 48}, + {11085, 1, 2, 47}, + {11089, 1, 2, 47}, + {11091, 1, 2, 47}, + {10376, 1, 2, 47}, + {10377, 1, 2, 47}, + {11127, 1, 2, 17}, + {11069, 1, 2, 17}, + {11142, 1, 2, 17}, + {11078, 1, 2, 17}, + {11056, 1, 2, 16}, + {11092, 1, 2, 16}, + {11159, 1, 2, 1200}, + {11159, 2, 2, 650}, + {11160, 1, 2, 800}, + {11160, 2, 2, 300}, + {11161, 1, 2, 100}, + {11161, 2, 2, 50}, + {11164, 1, 2, 100}, + {11162, 1, 2, 100}, + {11163, 1, 2, 100}, + {11158, 1, 2, 300}, + {11463, 1, 2, 300}, + {11356, 1, 2, 300}, + {11464, 1, 2, 300}, + {11357, 1, 2, 500}, + {11041, 1, 3, 266}, + {11047, 1, 3, 266}, + {11054, 1, 3, 266}, + {11065, 1, 3, 266}, + {11068, 1, 3, 266}, + {11075, 1, 3, 266}, + {11100, 1, 3, 266}, + {11106, 1, 3, 266}, + {11119, 1, 3, 266}, + {11135, 1, 3, 268}, + {11136, 1, 3, 268}, + {11138, 1, 3, 268}, + {11088, 1, 3, 268}, + {10370, 1, 3, 266}, + {10368, 1, 3, 268}, + {11043, 1, 3, 50}, + {11048, 1, 3, 50}, + {11050, 1, 3, 50}, + {11058, 1, 3, 50}, + {11060, 1, 3, 50}, + {11074, 1, 3, 50}, + {11107, 1, 3, 50}, + {11111, 1, 3, 50}, + {11113, 1, 3, 50}, + {11118, 1, 3, 50}, + {11126, 1, 3, 50}, + {11140, 1, 3, 50}, + {11086, 1, 3, 50}, + {11095, 1, 3, 50}, + {11055, 1, 3, 50}, + {10378, 1, 3, 50}, + {11052, 1, 3, 15}, + {11073, 1, 3, 15}, + {11146, 1, 3, 15}, + {11116, 1, 3, 15}, + {11123, 1, 3, 15}, + {11097, 1, 3, 15}, + {10367, 1, 3, 15}, + {10371, 1, 3, 15}, + {10373, 1, 3, 15}, + {10778, 1, 3, 375}, + {11209, 1, 3, 375}, + {10813, 1, 3, 375}, + {11389, 1, 3, 375}, + {11159, 1, 3, 1000}, + {11159, 2, 3, 250}, + {11160, 1, 3, 700}, + {11160, 2, 3, 175}, + {11161, 1, 3, 300}, + {11161, 2, 3, 75}, + {11465, 1, 3, 53}, + {11466, 1, 3, 27}, + {11467, 1, 3, 266}, + {11468, 1, 3, 533}, + {11469, 1, 3, 186}, + }, + 7002: { + {11037, 1, 1, 100}, + {11038, 1, 1, 100}, + {11044, 1, 1, 100}, + {11057, 1, 1, 100}, + {11059, 1, 1, 100}, + {11079, 1, 1, 100}, + {11098, 1, 1, 100}, + {11104, 1, 1, 100}, + {11117, 1, 1, 100}, + {11128, 1, 1, 100}, + {11133, 1, 1, 100}, + {11137, 1, 1, 100}, + {11143, 1, 1, 100}, + {11132, 1, 1, 100}, + {11042, 1, 1, 60}, + {11045, 1, 1, 60}, + {11064, 1, 1, 60}, + {11062, 1, 1, 60}, + {11070, 1, 1, 60}, + {11101, 1, 1, 60}, + {11108, 1, 1, 60}, + {11109, 1, 1, 60}, + {11120, 1, 1, 60}, + {11122, 1, 1, 60}, + {11134, 1, 1, 60}, + {11141, 1, 1, 60}, + {11084, 1, 1, 60}, + {11087, 1, 1, 60}, + {11094, 1, 1, 60}, + {10374, 1, 1, 60}, + {10375, 1, 1, 60}, + {11051, 1, 1, 20}, + {11071, 1, 1, 20}, + {11076, 1, 1, 20}, + {11102, 1, 1, 20}, + {11124, 1, 1, 20}, + {11090, 1, 1, 20}, + {11164, 1, 1, 400}, + {11162, 1, 1, 200}, + {11163, 1, 1, 200}, + {11463, 1, 1, 100}, + {11464, 1, 1, 150}, + {10355, 1, 1, 150}, + {12506, 1, 1, 200}, + {12507, 1, 1, 300}, + {12508, 1, 1, 900}, + {13629, 1, 1, 350}, + {13628, 1, 1, 200}, + {11356, 1, 1, 100}, + {11357, 1, 1, 150}, + {12014, 1, 1, 250}, + {12016, 1, 1, 400}, + {12015, 1, 1, 410}, + {11159, 2, 1, 500}, + {11159, 4, 1, 500}, + {11159, 6, 1, 500}, + {11160, 2, 1, 400}, + {11160, 4, 1, 400}, + {11160, 6, 1, 400}, + {11161, 2, 1, 100}, + {11161, 4, 1, 100}, + {11161, 6, 1, 100}, + {11039, 1, 2, 100}, + {11040, 1, 2, 100}, + {11049, 1, 2, 100}, + {11061, 1, 2, 100}, + {11063, 1, 2, 100}, + {11077, 1, 2, 100}, + {11099, 1, 2, 100}, + {11105, 1, 2, 100}, + {11129, 1, 2, 100}, + {11130, 1, 2, 100}, + {11131, 1, 2, 100}, + {11139, 1, 2, 100}, + {11145, 1, 2, 100}, + {11096, 1, 2, 100}, + {11046, 1, 2, 60}, + {11066, 1, 2, 60}, + {11067, 1, 2, 60}, + {11072, 1, 2, 60}, + {11082, 1, 2, 60}, + {11103, 1, 2, 60}, + {11110, 1, 2, 60}, + {11112, 1, 2, 60}, + {11114, 1, 2, 60}, + {11115, 1, 2, 60}, + {11121, 1, 2, 60}, + {11144, 1, 2, 60}, + {11085, 1, 2, 60}, + {11089, 1, 2, 60}, + {11091, 1, 2, 60}, + {10376, 1, 2, 60}, + {10377, 1, 2, 60}, + {11127, 1, 2, 20}, + {11069, 1, 2, 20}, + {11142, 1, 2, 20}, + {11078, 1, 2, 20}, + {11056, 1, 2, 20}, + {11092, 1, 2, 20}, + {11164, 1, 2, 400}, + {11162, 1, 2, 200}, + {11163, 1, 2, 200}, + {11463, 1, 2, 250}, + {11464, 1, 2, 350}, + {12506, 1, 2, 150}, + {12507, 1, 2, 200}, + {12508, 1, 2, 350}, + {13629, 1, 2, 250}, + {13628, 1, 2, 200}, + {10355, 1, 2, 400}, + {11158, 1, 2, 100}, + {11356, 1, 2, 100}, + {11357, 1, 2, 100}, + {12014, 1, 2, 300}, + {12016, 1, 2, 450}, + {12015, 1, 2, 460}, + {11159, 2, 2, 500}, + {11159, 4, 2, 500}, + {11159, 6, 2, 500}, + {11160, 2, 2, 400}, + {11160, 4, 2, 400}, + {11160, 6, 2, 400}, + {11161, 2, 2, 100}, + {11161, 4, 2, 100}, + {11161, 6, 2, 100}, + {11041, 1, 3, 120}, + {11047, 1, 3, 120}, + {11054, 1, 3, 120}, + {11065, 1, 3, 120}, + {11068, 1, 3, 120}, + {11075, 1, 3, 120}, + {11100, 1, 3, 120}, + {11106, 1, 3, 120}, + {11119, 1, 3, 120}, + {11135, 1, 3, 120}, + {11136, 1, 3, 120}, + {11138, 1, 3, 120}, + {11088, 1, 3, 120}, + {10370, 1, 3, 120}, + {10368, 1, 3, 120}, + {11043, 1, 3, 65}, + {11048, 1, 3, 65}, + {11050, 1, 3, 65}, + {11058, 1, 3, 65}, + {11060, 1, 3, 65}, + {11074, 1, 3, 65}, + {11107, 1, 3, 65}, + {11111, 1, 3, 65}, + {11113, 1, 3, 65}, + {11118, 1, 3, 65}, + {11126, 1, 3, 65}, + {11140, 1, 3, 65}, + {11086, 1, 3, 65}, + {11095, 1, 3, 65}, + {11055, 1, 3, 65}, + {10378, 1, 3, 65}, + {11052, 1, 3, 15}, + {11073, 1, 3, 15}, + {11146, 1, 3, 15}, + {11116, 1, 3, 15}, + {11123, 1, 3, 15}, + {11097, 1, 3, 15}, + {10367, 1, 3, 15}, + {10371, 1, 3, 15}, + {10373, 1, 3, 15}, + {10778, 3, 3, 490}, + {11209, 3, 3, 490}, + {10813, 3, 3, 490}, + {11389, 3, 3, 490}, + {12046, 3, 3, 500}, + {12503, 3, 3, 500}, + {11159, 2, 3, 500}, + {11159, 4, 3, 500}, + {11159, 6, 3, 500}, + {11160, 2, 3, 400}, + {11160, 4, 3, 400}, + {11160, 6, 3, 400}, + {11161, 2, 3, 100}, + {11161, 4, 3, 100}, + {11161, 6, 3, 100}, + {11465, 1, 3, 53}, + {11466, 1, 3, 27}, + {11467, 1, 3, 266}, + {11468, 1, 3, 533}, + {11469, 1, 3, 186}, + }, + 7011: { + {11037, 1, 1, 290}, + {11038, 1, 1, 270}, + {11044, 1, 1, 270}, + {11057, 1, 1, 290}, + {11059, 1, 1, 290}, + {11079, 1, 1, 290}, + {11098, 1, 1, 280}, + {11104, 1, 1, 300}, + {11117, 1, 1, 280}, + {11128, 1, 1, 290}, + {11133, 1, 1, 290}, + {11137, 1, 1, 300}, + {11143, 1, 1, 290}, + {11132, 1, 1, 270}, + {11042, 1, 1, 47}, + {11045, 1, 1, 47}, + {11064, 1, 1, 47}, + {11062, 1, 1, 47}, + {11070, 1, 1, 48}, + {11101, 1, 1, 47}, + {11108, 1, 1, 47}, + {11109, 1, 1, 47}, + {11120, 1, 1, 47}, + {11122, 1, 1, 47}, + {11134, 1, 1, 47}, + {11141, 1, 1, 47}, + {11084, 1, 1, 47}, + {11087, 1, 1, 47}, + {11094, 1, 1, 47}, + {10374, 1, 1, 47}, + {10375, 1, 1, 47}, + {11051, 1, 1, 17}, + {11071, 1, 1, 16}, + {11076, 1, 1, 16}, + {11102, 1, 1, 17}, + {11124, 1, 1, 17}, + {11090, 1, 1, 17}, + {11159, 1, 1, 1200}, + {11159, 2, 1, 650}, + {11160, 1, 1, 800}, + {11160, 2, 1, 300}, + {11161, 1, 1, 100}, + {11161, 2, 1, 50}, + {11164, 1, 1, 100}, + {11162, 1, 1, 100}, + {11163, 1, 1, 100}, + {11158, 1, 1, 300}, + {11463, 1, 1, 300}, + {11356, 1, 1, 300}, + {11464, 1, 1, 300}, + {11357, 1, 1, 500}, + {11039, 1, 2, 300}, + {11040, 1, 2, 270}, + {11049, 1, 2, 300}, + {11061, 1, 2, 290}, + {11063, 1, 2, 290}, + {11077, 1, 2, 290}, + {11099, 1, 2, 280}, + {11105, 1, 2, 300}, + {11129, 1, 2, 250}, + {11130, 1, 2, 300}, + {11131, 1, 2, 280}, + {11139, 1, 2, 290}, + {11145, 1, 2, 260}, + {11096, 1, 2, 300}, + {11046, 1, 2, 47}, + {11066, 1, 2, 47}, + {11067, 1, 2, 47}, + {11072, 1, 2, 47}, + {11082, 1, 2, 47}, + {11103, 1, 2, 47}, + {11110, 1, 2, 47}, + {11112, 1, 2, 47}, + {11114, 1, 2, 47}, + {11115, 1, 2, 47}, + {11121, 1, 2, 47}, + {11144, 1, 2, 48}, + {11085, 1, 2, 47}, + {11089, 1, 2, 47}, + {11091, 1, 2, 47}, + {10376, 1, 2, 47}, + {10377, 1, 2, 47}, + {11127, 1, 2, 17}, + {11069, 1, 2, 17}, + {11142, 1, 2, 17}, + {11078, 1, 2, 17}, + {11056, 1, 2, 16}, + {11092, 1, 2, 16}, + {11159, 1, 2, 1200}, + {11159, 2, 2, 650}, + {11160, 1, 2, 800}, + {11160, 2, 2, 300}, + {11161, 1, 2, 100}, + {11161, 2, 2, 50}, + {11164, 1, 2, 100}, + {11162, 1, 2, 100}, + {11163, 1, 2, 100}, + {11158, 1, 2, 300}, + {11463, 1, 2, 300}, + {11356, 1, 2, 300}, + {11464, 1, 2, 300}, + {11357, 1, 2, 500}, + {11041, 1, 3, 266}, + {11047, 1, 3, 266}, + {11054, 1, 3, 266}, + {11065, 1, 3, 266}, + {11068, 1, 3, 266}, + {11075, 1, 3, 266}, + {11100, 1, 3, 266}, + {11106, 1, 3, 266}, + {11119, 1, 3, 266}, + {11135, 1, 3, 268}, + {11136, 1, 3, 268}, + {11138, 1, 3, 268}, + {11088, 1, 3, 268}, + {10370, 1, 3, 266}, + {10368, 1, 3, 268}, + {11043, 1, 3, 50}, + {11048, 1, 3, 50}, + {11050, 1, 3, 50}, + {11058, 1, 3, 50}, + {11060, 1, 3, 50}, + {11074, 1, 3, 50}, + {11107, 1, 3, 50}, + {11111, 1, 3, 50}, + {11113, 1, 3, 50}, + {11118, 1, 3, 50}, + {11126, 1, 3, 50}, + {11140, 1, 3, 50}, + {11086, 1, 3, 50}, + {11095, 1, 3, 50}, + {11055, 1, 3, 50}, + {10378, 1, 3, 50}, + {11052, 1, 3, 15}, + {11073, 1, 3, 15}, + {11146, 1, 3, 15}, + {11116, 1, 3, 15}, + {11123, 1, 3, 15}, + {11097, 1, 3, 15}, + {10367, 1, 3, 15}, + {10371, 1, 3, 15}, + {10373, 1, 3, 15}, + {10778, 1, 3, 375}, + {11209, 1, 3, 375}, + {10813, 1, 3, 375}, + {11389, 1, 3, 375}, + {11159, 1, 3, 1000}, + {11159, 2, 3, 250}, + {11160, 1, 3, 700}, + {11160, 2, 3, 175}, + {11161, 1, 3, 300}, + {11161, 2, 3, 75}, + {11465, 1, 3, 53}, + {11466, 1, 3, 27}, + {11467, 1, 3, 266}, + {11468, 1, 3, 533}, + {11469, 1, 3, 186}, + }, + 7012: { + {11037, 1, 1, 290}, + {11038, 1, 1, 270}, + {11044, 1, 1, 270}, + {11057, 1, 1, 290}, + {11059, 1, 1, 290}, + {11079, 1, 1, 290}, + {11098, 1, 1, 280}, + {11104, 1, 1, 300}, + {11117, 1, 1, 280}, + {11128, 1, 1, 290}, + {11133, 1, 1, 290}, + {11137, 1, 1, 300}, + {11143, 1, 1, 290}, + {11132, 1, 1, 270}, + {11042, 1, 1, 47}, + {11045, 1, 1, 47}, + {11064, 1, 1, 47}, + {11062, 1, 1, 47}, + {11070, 1, 1, 48}, + {11101, 1, 1, 47}, + {11108, 1, 1, 47}, + {11109, 1, 1, 47}, + {11120, 1, 1, 47}, + {11122, 1, 1, 47}, + {11134, 1, 1, 47}, + {11141, 1, 1, 47}, + {11084, 1, 1, 47}, + {11087, 1, 1, 47}, + {11094, 1, 1, 47}, + {10374, 1, 1, 47}, + {10375, 1, 1, 47}, + {11051, 1, 1, 17}, + {11071, 1, 1, 16}, + {11076, 1, 1, 16}, + {11102, 1, 1, 17}, + {11124, 1, 1, 17}, + {11090, 1, 1, 17}, + {11159, 1, 1, 1200}, + {11159, 2, 1, 650}, + {11160, 1, 1, 800}, + {11160, 2, 1, 300}, + {11161, 1, 1, 100}, + {11161, 2, 1, 50}, + {11164, 1, 1, 100}, + {11162, 1, 1, 100}, + {11163, 1, 1, 100}, + {11158, 1, 1, 300}, + {11463, 1, 1, 300}, + {11356, 1, 1, 300}, + {11464, 1, 1, 300}, + {11357, 1, 1, 500}, + {11039, 1, 2, 300}, + {11040, 1, 2, 270}, + {11049, 1, 2, 300}, + {11061, 1, 2, 290}, + {11063, 1, 2, 290}, + {11077, 1, 2, 290}, + {11099, 1, 2, 280}, + {11105, 1, 2, 300}, + {11129, 1, 2, 250}, + {11130, 1, 2, 300}, + {11131, 1, 2, 280}, + {11139, 1, 2, 290}, + {11145, 1, 2, 260}, + {11096, 1, 2, 300}, + {11046, 1, 2, 47}, + {11066, 1, 2, 47}, + {11067, 1, 2, 47}, + {11072, 1, 2, 47}, + {11082, 1, 2, 47}, + {11103, 1, 2, 47}, + {11110, 1, 2, 47}, + {11112, 1, 2, 47}, + {11114, 1, 2, 47}, + {11115, 1, 2, 47}, + {11121, 1, 2, 47}, + {11144, 1, 2, 48}, + {11085, 1, 2, 47}, + {11089, 1, 2, 47}, + {11091, 1, 2, 47}, + {10376, 1, 2, 47}, + {10377, 1, 2, 47}, + {11127, 1, 2, 17}, + {11069, 1, 2, 17}, + {11142, 1, 2, 17}, + {11078, 1, 2, 17}, + {11056, 1, 2, 16}, + {11092, 1, 2, 16}, + {11159, 1, 2, 1200}, + {11159, 2, 2, 650}, + {11160, 1, 2, 800}, + {11160, 2, 2, 300}, + {11161, 1, 2, 100}, + {11161, 2, 2, 50}, + {11164, 1, 2, 100}, + {11162, 1, 2, 100}, + {11163, 1, 2, 100}, + {11158, 1, 2, 300}, + {11463, 1, 2, 300}, + {11356, 1, 2, 300}, + {11464, 1, 2, 300}, + {11357, 1, 2, 500}, + {11041, 1, 3, 266}, + {11047, 1, 3, 266}, + {11054, 1, 3, 266}, + {11065, 1, 3, 266}, + {11068, 1, 3, 266}, + {11075, 1, 3, 266}, + {11100, 1, 3, 266}, + {11106, 1, 3, 266}, + {11119, 1, 3, 266}, + {11135, 1, 3, 268}, + {11136, 1, 3, 268}, + {11138, 1, 3, 268}, + {11088, 1, 3, 268}, + {10370, 1, 3, 266}, + {10368, 1, 3, 268}, + {11043, 1, 3, 50}, + {11048, 1, 3, 50}, + {11050, 1, 3, 50}, + {11058, 1, 3, 50}, + {11060, 1, 3, 50}, + {11074, 1, 3, 50}, + {11107, 1, 3, 50}, + {11111, 1, 3, 50}, + {11113, 1, 3, 50}, + {11118, 1, 3, 50}, + {11126, 1, 3, 50}, + {11140, 1, 3, 50}, + {11086, 1, 3, 50}, + {11095, 1, 3, 50}, + {11055, 1, 3, 50}, + {10378, 1, 3, 50}, + {11052, 1, 3, 15}, + {11073, 1, 3, 15}, + {11146, 1, 3, 15}, + {11116, 1, 3, 15}, + {11123, 1, 3, 15}, + {11097, 1, 3, 15}, + {10367, 1, 3, 15}, + {10371, 1, 3, 15}, + {10373, 1, 3, 15}, + {10778, 1, 3, 375}, + {11209, 1, 3, 375}, + {10813, 1, 3, 375}, + {11389, 1, 3, 375}, + {11159, 1, 3, 1000}, + {11159, 2, 3, 250}, + {11160, 1, 3, 700}, + {11160, 2, 3, 175}, + {11161, 1, 3, 300}, + {11161, 2, 3, 75}, + {11465, 1, 3, 53}, + {11466, 1, 3, 27}, + {11467, 1, 3, 266}, + {11468, 1, 3, 533}, + {11469, 1, 3, 186}, + }, +} + +type PaperMissionTimetable struct { + Start time.Time + End time.Time +} + +type PaperMissionData struct { + Unk0 uint8 + Unk1 uint8 + Unk2 int16 + Reward1ID uint16 + Reward1Quantity uint8 + Reward2ID uint16 + Reward2Quantity uint8 +} + +type PaperMission struct { + Timetables []PaperMissionTimetable + Data []PaperMissionData +} + +type PaperData struct { + Unk0 uint16 + Unk1 int16 + Unk2 int16 + Unk3 int16 + Unk4 int16 + Unk5 int16 + Unk6 int16 +} + +type PaperGift struct { + Unk0 uint16 + Unk1 uint8 + Unk2 uint8 + Unk3 uint16 +} + func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) { - // if the game gets bad responses for this it breaks the ability to save pkt := p.(*mhfpacket.MsgMhfGetPaperData) - var data []byte - var err error - if pkt.Unk2 == 4 { - data, err = hex.DecodeString("0A218EAD000000000000000000000000") - } else if pkt.Unk2 == 5 { - data, err = hex.DecodeString("0A218EAD00000000000000000000003403E900010000000000000000000003E900020000000000000000000003EB00010064006400C80064000003EB00020096006400F00064000003EC000A270F002800000000000003ED000A01F4000000000000000003EF00010000000000000000000003F000C801900BB801900BB8000003F200010FA0000000000000000003F200020FA0000000000000000003F3000117703A984E2061A8753003F3000217703A984E2061A8753003F400011F40445C57E46B6C791803F400021F40445C57E46B6C791803F700010010001000100000000003F7000200100010001000000000044D000107E001F4000000000000044D000207E001F4000000000000044F0001000000000BB800000BB8044F0002000000000BB800000BB804500001000A270F00280000000004500002000A270F00280000000004510001000A01F400000000000004510002000A01F400000000000007D100010011003A0000000602BC07D100010014003A0000000300C807D100010016003A0000000700FA07D10001001B003A00000001006407D100010035003A0000000803E807D100010043003A0000000901F407D100010044003A00000002009607D10001004A003A0000000400C807D10001004B003A0000000501F407D10001004C003A0000000A032007D100010050003A0000000B038407D100010059003A0000000C025807D100020011003C0000000602BC07D100020014003C0000000300C807D100020016003C00000007015E07D10002001B003C00000001006407D100020027003C0000000D00C807D100020028003C0000000F025807D100020035003C0000000803E807D100020043003C0000000201F407D100020044003C00000009009607D10002004A003C0000000400C807D10002004B003C0000000501F407D10002004C003C0000000A032007D100020050003C0000000B038407D100020051003C0000000E038407D100020059003C0000000C025807D10002005E003C0000001003E8") - } else if pkt.Unk2 == 6 { - data, err = hex.DecodeString("0A218EAD0000000000000000000001A503EA00640000000000000000000003EE00012710271000000000000003EE000227104E2000000000000003F100140000000000000000000003F5000100010001006400C8012C03F5000100010002006400C8012C03F5000100020001012C006400C803F5000100020002012C006400C803F500010003000100C8012C006403F500010003000200C8012C006403F5000200010001012C006400C803F5000200010002012C006400C803F500020002000100C8012C006403F500020002000200C8012C006403F5000200030001006400C8012C03F5000200030002006400C8012C03F500030001000100C8012C006403F500030001000200C8012C006403F5000300020001006400C8012C03F5000300020002006400C8012C03F5000300030001012C006400C803F5000300030002012C006400C803F800010001005000000000000003F800010002005000000000000003F800010003005000000000000003F800020001005000000000000003F800020002005000000000000003F800020003005000000000000004B10001003C003200000000000004B10002003C003200000000000004B200010000000500320000000004B2000100060014003C0000000004B200010015002800460000000004B200010029007800500000000004B20001007900A0005A0000000004B2000100A100FA00640000000004B2000100FB01F400640000000004B2000101F5270F00640000000004B200020000006400640000000004B20002006500C800640000000004B2000200C901F400960000000004B2000201F5270F00960000000004B3000100000005000A0000000004B300010006000A00140000000004B30001000B001E001E0000000004B30001001F003C00280000000004B30001003D007800320000000004B3000100790082003C0000000004B300010083008C00460000000004B30001008D009600500000000004B30001009700A000550000000004B3000100A100C800640000000004B3000100C901F400640000000004B3000101F5270F00640000000004B300020000007800460000000004B30002007901F400780000000004B3000201F5270F00780000000004B4000100000005000F0000000004B400010006000A00140000000004B40001000B000F00190000000004B4000100100014001B0000000004B4000100150019001E0000000004B40001001A001E00200000000004B40001001F002800230000000004B400010029003200250000000004B400010033003C00280000000004B40001003D0046002B0000000004B4000100470050002D0000000004B400010051005A002F0000000004B40001005B006400320000000004B400010065006E003C0000000004B40001006F007800460000000004B4000100790082004B0000000004B400010083008C00520000000004B40001008D00A000550000000004B4000100A100C800640000000004B4000100C901F400640000000004B4000101F5270F00640000000004B400020000007800460000000004B40002007901F400780000000004B4000201F5270F0078000000000FA10001000000000000000000000FA10002000029AB0005000000010FA10002000029AB0005000000010FA10002000029AB0005000000010FA10002000029AB0005000000010FA10002000029AC0002000000010FA10002000029AC0002000000010FA10002000029AC0002000000010FA10002000029AC0002000000010FA10002000029AD0001000000010FA10002000029AD0001000000010FA10002000029AD0001000000010FA10002000029AD0001000000010FA10002000029AF0003000000010FA10002000029AF0003000000010FA10002000029AF0003000000010FA10002000029AF0003000000010FA10002000028900001000000010FA10002000028900001000000010FA10002000029AE0002000000010FA10002000029AE0002000000010FA10002000029BA0002000000010FA10002000029BB0002000000010FA10002000029B60001000000010FA10002000029B60001000000010FA5000100002B970001138800010FA5000100002B9800010D1600010FA5000100002B99000105DC00010FA5000100002B9A0001006400010FA5000100002B9B0001003200010FA5000200002B970002070800010FA5000200002B98000204B000010FA5000200002B99000201F400010FA5000200002B9A0001003200010FA5000200002B1D0001009600010FA5000200002B1E0001009600010FA5000200002B240001009600010FA5000200002B310001009600010FA5000200002B330001009600010FA5000200002B470001009600010FA5000200002B5A0001009600010FA5000200002B600001009600010FA5000200002B6D0001009600010FA5000200002B780001009600010FA5000200002B7D0001009600010FA5000200002B810001009600010FA5000200002B870001009600010FA5000200002B7C0001009600010FA5000200002B1F0001009600010FA5000200002B200001009600010FA5000200002B290001009600010FA5000200002B350001009600010FA5000200002B370001009600010FA5000200002B450001009600010FA5000200002B5B0001009600010FA5000200002B610001009600010FA5000200002B790001009600010FA5000200002B7A0001009600010FA5000200002B7B0001009600010FA5000200002B830001009600010FA5000200002B890001009600010FA5000200002B580001009600010FA5000200002B210001009600010FA5000200002B270001009600010FA5000200002B2E0001009600010FA5000200002B390001009600010FA5000200002B3C0001009600010FA5000200002B430001009600010FA5000200002B5C0001009600010FA5000200002B620001009600010FA5000200002B6F0001009600010FA5000200002B7F0001009600010FA5000200002B800001009600010FA5000200002B820001009600010FA5000200002B500001009600010FA50002000028820001009600010FA50002000028800001009600010FA6000100002B970001138800010FA6000100002B9800010D1600010FA6000100002B99000105DC00010FA6000100002B9A0001006400010FA6000100002B9B0001003200010FA6000200002B970002070800010FA6000200002B98000204B000010FA6000200002B99000201F400010FA6000200002B9A0001003200010FA6000200002B1D0001009600010FA6000200002B1E0001009600010FA6000200002B240001009600010FA6000200002B310001009600010FA6000200002B330001009600010FA6000200002B470001009600010FA6000200002B5A0001009600010FA6000200002B600001009600010FA6000200002B6D0001009600010FA6000200002B780001009600010FA6000200002B7D0001009600010FA6000200002B810001009600010FA6000200002B870001009600010FA6000200002B7C0001009600010FA6000200002B1F0001009600010FA6000200002B200001009600010FA6000200002B290001009600010FA6000200002B350001009600010FA6000200002B370001009600010FA6000200002B450001009600010FA6000200002B5B0001009600010FA6000200002B610001009600010FA6000200002B790001009600010FA6000200002B7A0001009600010FA6000200002B7B0001009600010FA6000200002B830001009600010FA6000200002B890001009600010FA6000200002B580001009600010FA6000200002B210001009600010FA6000200002B270001009600010FA6000200002B2E0001009600010FA6000200002B390001009600010FA6000200002B3C0001009600010FA6000200002B430001009600010FA6000200002B5C0001009600010FA6000200002B620001009600010FA6000200002B6F0001009600010FA6000200002B7F0001009600010FA6000200002B800001009600010FA6000200002B820001009600010FA6000200002B500001009600010FA60002000028820001009600010FA60002000028800001009600010FA7000100002B320001004600010FA7000100002B340001004600010FA7000100002B360001004600010FA7000100002B380001004600010FA7000100002B3A0001004600010FA7000100002B6E0001004600010FA7000100002B700001004600010FA7000100002B660001004600010FA7000100002B680001004600010FA7000100002B6A0001004600010FA7000100002B220001004600010FA7000100002B230001004600010FA7000100002B420001004600010FA7000100002B840001004600010FA7000100002B3B0001004600010FA7000100002B280001004600010FA7000100002B260001004600010FA7000100002B5F0001004600010FA7000100002B630001004600010FA7000100002B640001004600010FA7000100002B710001004600010FA7000100002B7E0001004600010FA7000100002B4C0001004600010FA7000100002B4D0001004600010FA7000100002B4E0001004600010FA7000100002B4F0001004600010FA7000100002B560001004600010FA7000100002B570001004600010FA70001000028860001004600010FA70001000028870001004600010FA70001000028880001004600010FA70001000028890001004600010FA700010000288A0001004600010FA7000100002B3D0001002D00010FA7000100002B3F0001002D00010FA7000100002B410001002D00010FA7000100002B440001002D00010FA7000100002B460001002D00010FA7000100002B6C0001002D00010FA7000100002B730001002D00010FA7000100002B770001002D00010FA7000100002B860001002D00010FA7000100002B300001002D00010FA7000100002B520001002D00010FA7000100002B590001002D00010FA700010000287F0001002D00010FA70001000028830001002D00010FA70001000028850001002D00010FA7000100002B480001000F00010FA7000100002B490001000F00010FA7000100002B4B0001000F00010FA7000100002B750001000F00010FA7000100002B550001000E00010FA7000100002B2D0001000A00010FA7000100002B8B0001000A00010FA70001000028840001000500010FA70001000028810001000100010FA7000100002B9B0001009600010FA7000100002CC90001003200010FA7000100002CCA0001001900010FA7000100002CCB000100C800010FA7000100002CCC0001019000010FA7000100002CCD0001009600010FA7000100002B1D0001005C00010FA7000100002B1E0001005C00010FA7000100002B240001005C00010FA7000100002B310001005C00010FA7000100002B330001005C00010FA7000100002B470001005C00010FA7000100002B5A0001005C00010FA7000100002B600001005C00010FA7000100002B6D0001005C00010FA7000100002B7D0001005C00010FA7000100002B810001005C00010FA7000100002B870001005C00010FA7000100002B7C0001005C00010FA7000100002B1F0001005C00010FA7000100002B200001005C00010FA7000100002B290001005C00010FA7000100002B350001005C00010FA7000100002B370001005C00010FA7000100002B450001005C00010FA7000100002B5B0001005C00010FA7000100002B610001005C00010FA7000100002B790001005C00010FA7000100002B7A0001005C00010FA7000100002B7B0001005C00010FA7000100002B830001005C00010FA7000100002B890001005B00010FA7000100002B580001005B00010FA7000100002B210001005B00010FA7000100002B270001005B00010FA7000100002B2E0001005B00010FA7000100002B390001005B00010FA7000100002B3C0001005B00010FA7000100002B430001005B00010FA7000100002B5C0001005B00010FA7000100002B620001005B00010FA7000100002B6F0001005B00010FA7000100002B7F0001005B00010FA7000100002B800001005B00010FA7000100002B820001005B00010FA7000100002B500001005B00010FA70001000028820001005B00010FA70001000028800001005B00010FA7000100002B250001005B00010FA7000100002B3E0001005B00010FA7000100002B5D0001005B00010FA7000100002B650001005B00010FA7000100002B720001005B00010FA7000100002B850001005B00010FA7000100002B2B0001005B00010FA7000100002B5E0001005B00010FA7000100002B740001005B00010FA7000100002B400001005B00010FA7000100002B4A0001005B00010FA7000100002B6B0001005B00010FA7000100002B880001005B00010FA7000100002B510001005B00010FA7000100002B530001005B00010FA7000100002B540001005B00010FA7000100002B2A0001005B00010FA7000100002B670001005B00010FA7000100002B690001005B00010FA7000100002B760001005B00010FA7000100002B2F0001005B00010FA7000100002B2C0001005B00010FA7000100002B8A0001005B00010FA7000200002B320001005A00010FA7000200002B340001005A00010FA7000200002B360001005A00010FA7000200002B380001005A00010FA7000200002B3A0001005A00010FA7000200002B6E0001005A00010FA7000200002B700001005A00010FA7000200002B660001005A00010FA7000200002B680001005A00010FA7000200002B6A0001005A00010FA7000200002B220001005A00010FA7000200002B230001005A00010FA7000200002B420001005A00010FA7000200002B840001005A00010FA7000200002B3B0001005A00010FA7000200002B280001005A00010FA7000200002B260001005A00010FA7000200002B5F0001005A00010FA7000200002B630001005A00010FA7000200002B640001005A00010FA7000200002B710001005A00010FA7000200002B7E0001005A00010FA7000200002B4C0001005A00010FA7000200002B4D0001005A00010FA7000200002B4E0001005A00010FA7000200002B4F0001005A00010FA7000200002B560001005A00010FA7000200002B570001005A00010FA70002000028860001005A00010FA70002000028870001005A00010FA70002000028880001005A00010FA70002000028890001005A00010FA700020000288A0001005A00010FA7000200002B3D0001005000010FA7000200002B3F0001005000010FA7000200002B410001005000010FA7000200002B440001005000010FA7000200002B460001005000010FA7000200002B6C0001005000010FA7000200002B730001005000010FA7000200002B770001005000010FA7000200002B860001005000010FA7000200002B300001005000010FA7000200002B520001005000010FA7000200002B590001005000010FA700020000287F0001005000010FA70002000028830001005000010FA70002000028850001005000010FA7000200002B480001001600010FA7000200002B490001001600010FA7000200002B4B0001001600010FA7000200002B750001001600010FA7000200002B550001001600010FA7000200002B2D0001000F00010FA7000200002B8B0001000F00010FA70002000028840001000800010FA70002000028810001000200010FA7000200002B97000304C400010FA7000200002B980003028A00010FA7000200002B99000300A000010FA7000200002D8D0001032000010FA7000200002D8E0001032000010FA7000200002B9B000101F400010FA7000200002B9A0001022600010FA7000200002CC90001003200010FA7000200002CCA0001001900010FA7000200002CCB000100FA00010FA7000200002CCC000101F400010FA7000200002CCD000100AF0001106A000100002B9B000117700001106A000100002CC9000100C80001106A000100002CCA000100640001106A000100002CCB000103E80001106A000100002CCC000107D00001106A000100002CCD000102BC0001106A000200002D8D000103200001106A000200002D8E000103200001106A000200002B9B000101900001106A000200002CC9000101900001106A000200002CCA000100C80001106A000200002CCB000107D00001106A000200002CCC00010FA00001106A000200002CCD000105780001") - } else if pkt.Unk2 == 6001 { - data, err = hex.DecodeString("0A218EAD0000000000000000000000052B97010113882B9801010D162B99010105DC2B9A010100642B9B01010032") - } else if pkt.Unk2 == 6002 { - data, err = hex.DecodeString("0A218EAD00000000000000000000002F2B97020107082B98020104B02B99020101F42B9A010100322B1D010100962B1E010100962B24010100962B31010100962B33010100962B47010100962B5A010100962B60010100962B6D010100962B78010100962B7D010100962B81010100962B87010100962B7C010100962B1F010100962B20010100962B29010100962B35010100962B37010100962B45010100962B5B010100962B61010100962B79010100962B7A010100962B7B010100962B83010100962B89010100962B58010100962B21010100962B27010100962B2E010100962B39010100962B3C010100962B43010100962B5C010100962B62010100962B6F010100962B7F010100962B80010100962B82010100962B5001010096288201010096288001010096") - } else if pkt.Unk2 == 6010 { - data, err = hex.DecodeString("0A218EAD00000000000000000000000B2B9701010E742B9801010B542B99010105142CBD010100FA2CBE010100FA2F17010100FA2F21010100FA2F1A010100FA2F24010100FA2DFE010100C82DFD01010190") - } else if pkt.Unk2 == 6011 { - data, err = hex.DecodeString("0A218EAD00000000000000000000000B2B9701010E742B9801010B542B99010105142CBD010100FA2CBE010100FA2F17010100FA2F21010100FA2F1A010100FA2F24010100FA2DFE010100C82DFD01010190") - } else if pkt.Unk2 == 6012 { - data, err = hex.DecodeString("0A218EAD00000000000000000000000D2B9702010DAC2B9802010B542B990201051430DC010101902CBD010100C82CBE010100C82F17010100C82F21010100C82F1A010100C82F24010100C82DFF010101902E00010100C82E0101010064") - } else if pkt.Unk2 == 7001 { - data, err = hex.DecodeString("0A218EAD00000000000000000000009D2B1D010101222B1E0101010E2B240101010E2B31010101222B33010101222B47010101222B5A010101182B600101012C2B6D010101182B78010101222B7D010101222B810101012C2B87010101222B7C0101010E2B220101002F2B250101002F2B380101002F2B360101002F2B3E010100302B5D0101002F2B640101002F2B650101002F2B700101002F2B720101002F2B7E0101002F2B850101002F2B4C0101002F2B4F0101002F2B560101002F28860101002F28870101002F2B2B010100112B3F010100102B44010100102B5E010100112B74010100112B52010100112B97010104B02B970201028A2B98010103202B980201012C2B99010100642B99020100322B9C010100642B9A010100642B9B010100642B960101012C2CC70101012C2C5C0101012C2CC80101012C2C5D010101F42B1F0102012C2B200102010E2B290102012C2B35010201222B37010201222B45010201222B5B010201182B610102012C2B79010200FA2B7A0102012C2B7B010201182B83010201222B89010201042B580102012C2B260102002F2B3A0102002F2B3B0102002F2B400102002F2B4A0102002F2B5F0102002F2B660102002F2B680102002F2B6A0102002F2B6B0102002F2B710102002F2B88010200302B4D0102002F2B510102002F2B530102002F28880102002F28890102002F2B77010200112B3D010200112B86010200112B46010200112B30010200102B54010200102B97010204B02B970202028A2B98010203202B980202012C2B99010200642B99020200322B9C010200642B9A010200642B9B010200642B960102012C2CC70102012C2C5C0102012C2CC80102012C2C5D010201F42B210103010A2B270103010A2B2E0103010A2B390103010A2B3C0103010A2B430103010A2B5C0103010A2B620103010A2B6F0103010A2B7F0103010C2B800103010C2B820103010C2B500103010C28820103010A28800103010C2B23010300322B28010300322B2A010300322B32010300322B34010300322B42010300322B63010300322B67010300322B69010300322B6E010300322B76010300322B84010300322B4E010300322B57010300322B2F01030032288A010300322B2C0103000F2B410103000F2B8A0103000F2B6C0103000F2B730103000F2B590103000F287F0103000F28830103000F28850103000F2A1A010301772BC9010301772A3D010301772C7D010301772B97010303E82B97020300FA2B98010302BC2B98020300AF2B990103012C2B990203004B2CC9010300352CCA0103001B2CCB0103010A2CCC010302152CCD010300BA") - } else if pkt.Unk2 == 7002 { - data, err = hex.DecodeString("0A218EAD0000000000000000000000B92B1D010100642B1E010100642B24010100642B31010100642B33010100642B47010100642B5A010100642B60010100642B6D010100642B78010100642B7D010100642B81010100642B87010100642B7C010100642B220101003C2B250101003C2B380101003C2B360101003C2B3E0101003C2B5D0101003C2B640101003C2B650101003C2B700101003C2B720101003C2B7E0101003C2B850101003C2B4C0101003C2B4F0101003C2B560101003C28860101003C28870101003C2B2B010100142B3F010100142B44010100142B5E010100142B74010100142B52010100142B9C010101902B9A010100C82B9B010100C82CC7010100642CC80101009628730101009630DA010100C830DB0101012C30DC01010384353D0101015E353C010100C82C5C010100642C5D010100962EEE010100FA2EF0010101902EEF0101019A2B97020101F42B97040101F42B97060101F42B98020101902B98040101902B98060101902B99020100642B99040100642B99060100642B1F010200642B20010200642B29010200642B35010200642B37010200642B45010200642B5B010200642B61010200642B79010200642B7A010200642B7B010200642B83010200642B89010200642B58010200642B260102003C2B3A0102003C2B3B0102003C2B400102003C2B4A0102003C2B5F0102003C2B660102003C2B680102003C2B6A0102003C2B6B0102003C2B710102003C2B880102003C2B4D0102003C2B510102003C2B530102003C28880102003C28890102003C2B77010200142B3D010200142B86010200142B46010200142B30010200142B54010200142B9C010201902B9A010200C82B9B010200C82CC7010200FA2CC80102015E30DA0102009630DB010200C830DC0102015E353D010200FA353C010200C82873010201902B96010200642C5C010200642C5D010200642EEE0102012C2EF0010201C22EEF010201CC2B97020201F42B97040201F42B97060201F42B98020201902B98040201902B98060201902B99020200642B99040200642B99060200642B21010300782B27010300782B2E010300782B39010300782B3C010300782B43010300782B5C010300782B62010300782B6F010300782B7F010300782B80010300782B82010300782B50010300782882010300782880010300782B23010300412B28010300412B2A010300412B32010300412B34010300412B42010300412B63010300412B67010300412B69010300412B6E010300412B76010300412B84010300412B4E010300412B57010300412B2F01030041288A010300412B2C0103000F2B410103000F2B8A0103000F2B6C0103000F2B730103000F2B590103000F287F0103000F28830103000F28850103000F2A1A030301EA2BC9030301EA2A3D030301EA2C7D030301EA2F0E030301F430D7030301F42B97020301F42B97040301F42B97060301F42B98020301902B98040301902B98060301902B99020300642B99040300642B99060300642CC9010300352CCA0103001B2CCB0103010A2CCC010302152CCD010300BA") - } else if pkt.Unk2 == 7011 { - data, err = hex.DecodeString("0A218EAD00000000000000000000009D2B1D010101222B1E0101010E2B240101010E2B31010101222B33010101222B47010101222B5A010101182B600101012C2B6D010101182B78010101222B7D010101222B810101012C2B87010101222B7C0101010E2B220101002F2B250101002F2B380101002F2B360101002F2B3E010100302B5D0101002F2B640101002F2B650101002F2B700101002F2B720101002F2B7E0101002F2B850101002F2B4C0101002F2B4F0101002F2B560101002F28860101002F28870101002F2B2B010100112B3F010100102B44010100102B5E010100112B74010100112B52010100112B97010104B02B970201028A2B98010103202B980201012C2B99010100642B99020100322B9C010100642B9A010100642B9B010100642B960101012C2CC70101012C2C5C0101012C2CC80101012C2C5D010101F42B1F0102012C2B200102010E2B290102012C2B35010201222B37010201222B45010201222B5B010201182B610102012C2B79010200FA2B7A0102012C2B7B010201182B83010201222B89010201042B580102012C2B260102002F2B3A0102002F2B3B0102002F2B400102002F2B4A0102002F2B5F0102002F2B660102002F2B680102002F2B6A0102002F2B6B0102002F2B710102002F2B88010200302B4D0102002F2B510102002F2B530102002F28880102002F28890102002F2B77010200112B3D010200112B86010200112B46010200112B30010200102B54010200102B97010204B02B970202028A2B98010203202B980202012C2B99010200642B99020200322B9C010200642B9A010200642B9B010200642B960102012C2CC70102012C2C5C0102012C2CC80102012C2C5D010201F42B210103010A2B270103010A2B2E0103010A2B390103010A2B3C0103010A2B430103010A2B5C0103010A2B620103010A2B6F0103010A2B7F0103010C2B800103010C2B820103010C2B500103010C28820103010A28800103010C2B23010300322B28010300322B2A010300322B32010300322B34010300322B42010300322B63010300322B67010300322B69010300322B6E010300322B76010300322B84010300322B4E010300322B57010300322B2F01030032288A010300322B2C0103000F2B410103000F2B8A0103000F2B6C0103000F2B730103000F2B590103000F287F0103000F28830103000F28850103000F2A1A010301772BC9010301772A3D010301772C7D010301772B97010303E82B97020300FA2B98010302BC2B98020300AF2B990103012C2B990203004B2CC9010300352CCA0103001B2CCB0103010A2CCC010302152CCD010300BA") - } else if pkt.Unk2 == 7012 { - data, err = hex.DecodeString("0A218EAD00000000000000000000009D2B1D010101222B1E0101010E2B240101010E2B31010101222B33010101222B47010101222B5A010101182B600101012C2B6D010101182B78010101222B7D010101222B810101012C2B87010101222B7C0101010E2B220101002F2B250101002F2B380101002F2B360101002F2B3E010100302B5D0101002F2B640101002F2B650101002F2B700101002F2B720101002F2B7E0101002F2B850101002F2B4C0101002F2B4F0101002F2B560101002F28860101002F28870101002F2B2B010100112B3F010100102B44010100102B5E010100112B74010100112B52010100112B97010104B02B970201028A2B98010103202B980201012C2B99010100642B99020100322B9C010100642B9A010100642B9B010100642B960101012C2CC70101012C2C5C0101012C2CC80101012C2C5D010101F42B1F0102012C2B200102010E2B290102012C2B35010201222B37010201222B45010201222B5B010201182B610102012C2B79010200FA2B7A0102012C2B7B010201182B83010201222B89010201042B580102012C2B260102002F2B3A0102002F2B3B0102002F2B400102002F2B4A0102002F2B5F0102002F2B660102002F2B680102002F2B6A0102002F2B6B0102002F2B710102002F2B88010200302B4D0102002F2B510102002F2B530102002F28880102002F28890102002F2B77010200112B3D010200112B86010200112B46010200112B30010200102B54010200102B97010204B02B970202028A2B98010203202B980202012C2B99010200642B99020200322B9C010200642B9A010200642B9B010200642B960102012C2CC70102012C2C5C0102012C2CC80102012C2C5D010201F42B210103010A2B270103010A2B2E0103010A2B390103010A2B3C0103010A2B430103010A2B5C0103010A2B620103010A2B6F0103010A2B7F0103010C2B800103010C2B820103010C2B500103010C28820103010A28800103010C2B23010300322B28010300322B2A010300322B32010300322B34010300322B42010300322B63010300322B67010300322B69010300322B6E010300322B76010300322B84010300322B4E010300322B57010300322B2F01030032288A010300322B2C0103000F2B410103000F2B8A0103000F2B6C0103000F2B730103000F2B590103000F287F0103000F28830103000F28850103000F2A1A010301772BC9010301772A3D010301772C7D010301772B97010303E82B97020300FA2B98010302BC2B98020300AF2B990103012C2B990203004B2CC9010300352CCA0103001B2CCB0103010A2CCC010302152CCD010300BA") + var data []*byteframe.ByteFrame + + var paperData []PaperData + var paperMissions PaperMission + var paperGift []PaperGift + + switch pkt.Unk2 { + case 0: + paperMissions = PaperMission{ + []PaperMissionTimetable{{TimeMidnight(), TimeMidnight().Add(24 * time.Hour)}}, + []PaperMissionData{}, + } + case 5: + paperData = []PaperData{ + // getTowerQuestTowerLevel + {1001, 1, 0, 0, 0, 0, 0}, + {1001, 2, 0, 0, 0, 0, 0}, + // iniTQT + {1003, 1, 100, 100, 200, 100, 0}, + {1003, 2, 150, 100, 240, 100, 0}, + {1004, 10, 9999, 40, 0, 0, 0}, + {1005, 10, 500, 0, 0, 0, 0}, + // getPaperDataSetFromProp + {1007, 1, 0, 0, 0, 0, 0}, + {1008, 200, 400, 3000, 400, 3000, 0}, + // getPaperDataSetParam1 / Dure Goal + {1010, 1, 4000, 0, 0, 0, 0}, + {1010, 2, 4000, 0, 0, 0, 0}, + // update_disp_flag / getPaperDataSetParam1 + {1011, 1, 6000, 15000, 20000, 25000, 30000}, + {1011, 2, 6000, 15000, 20000, 25000, 30000}, + {1012, 1, 8000, 17500, 22500, 27500, 31000}, + {1012, 2, 8000, 17500, 22500, 27500, 31000}, + // setServerZako + {1015, 1, 16, 16, 16, 0, 0}, + {1015, 2, 16, 16, 16, 0, 0}, + // createTowerFloorRandomNumberArray + {1101, 1, 2016, 500, 0, 0, 0}, + {1101, 2, 2016, 500, 0, 0, 0}, + // HRP/SRP/GRP/GSRP/TRP reward + {1103, 1, 0, 0, 3000, 0, 3000}, + {1103, 2, 0, 0, 3000, 0, 3000}, + // getTowerNextVenomLevel + {1104, 1, 10, 9999, 40, 0, 0}, + {1104, 2, 10, 9999, 40, 0, 0}, + {1105, 1, 10, 500, 0, 0, 0}, + {1105, 2, 10, 500, 0, 0, 0}, + // setServerBoss + {2001, 1, 17, 58, 0, 6, 700}, + {2001, 1, 20, 58, 0, 3, 200}, + {2001, 1, 22, 58, 0, 7, 250}, + {2001, 1, 27, 58, 0, 1, 100}, + {2001, 1, 53, 58, 0, 8, 1000}, + {2001, 1, 67, 58, 0, 9, 500}, + {2001, 1, 68, 58, 0, 2, 150}, + {2001, 1, 74, 58, 0, 4, 200}, + {2001, 1, 75, 58, 0, 5, 500}, + {2001, 1, 76, 58, 0, 10, 800}, + {2001, 1, 80, 58, 0, 11, 900}, + {2001, 1, 89, 58, 0, 12, 600}, + {2001, 2, 17, 60, 0, 6, 700}, + {2001, 2, 20, 60, 0, 3, 200}, + {2001, 2, 22, 60, 0, 7, 350}, + {2001, 2, 27, 60, 0, 1, 100}, + {2001, 2, 39, 60, 0, 13, 200}, + {2001, 2, 40, 60, 0, 15, 600}, + {2001, 2, 53, 60, 0, 8, 1000}, + {2001, 2, 67, 60, 0, 2, 500}, + {2001, 2, 68, 60, 0, 9, 150}, + {2001, 2, 74, 60, 0, 4, 200}, + {2001, 2, 75, 60, 0, 5, 500}, + {2001, 2, 76, 60, 0, 10, 800}, + {2001, 2, 80, 60, 0, 11, 900}, + {2001, 2, 81, 60, 0, 14, 900}, + {2001, 2, 89, 60, 0, 12, 600}, + {2001, 2, 94, 60, 0, 16, 1000}, + } + case 6: + paperData = []PaperData{ + // updateClearTowerFloor + {1002, 100, 0, 0, 0, 0, 0}, + // give_gem_func + {1006, 1, 10000, 10000, 0, 0, 0}, + {1006, 2, 10000, 20000, 0, 0, 0}, + {1009, 20, 0, 0, 0, 0, 0}, + // ttcStageInitDRP + {1013, 1, 1, 1, 100, 200, 300}, + {1013, 1, 1, 2, 100, 200, 300}, + {1013, 1, 2, 1, 300, 100, 200}, + {1013, 1, 2, 2, 300, 100, 200}, + {1013, 1, 3, 1, 200, 300, 100}, + {1013, 1, 3, 2, 200, 300, 100}, + {1013, 2, 1, 1, 300, 100, 200}, + {1013, 2, 1, 2, 300, 100, 200}, + {1013, 2, 2, 1, 200, 300, 100}, + {1013, 2, 2, 2, 200, 300, 100}, + {1013, 2, 3, 1, 100, 200, 300}, + {1013, 2, 3, 2, 100, 200, 300}, + {1013, 3, 1, 1, 200, 300, 100}, + {1013, 3, 1, 2, 200, 300, 100}, + {1013, 3, 2, 1, 100, 200, 300}, + {1013, 3, 2, 2, 100, 200, 300}, + {1013, 3, 3, 1, 300, 100, 200}, + {1013, 3, 3, 2, 300, 100, 200}, + {1016, 1, 1, 80, 0, 0, 0}, + {1016, 1, 2, 80, 0, 0, 0}, + {1016, 1, 3, 80, 0, 0, 0}, + {1016, 2, 1, 80, 0, 0, 0}, + {1016, 2, 2, 80, 0, 0, 0}, + {1016, 2, 3, 80, 0, 0, 0}, + {1201, 1, 60, 50, 0, 0, 0}, + {1201, 2, 60, 50, 0, 0, 0}, + // Gimmick Damage {ID, Block, StartFloor, EndFloor, Multiplier*100, Unk, Unk} + {1202, 1, 0, 5, 50, 0, 0}, + {1202, 1, 6, 20, 60, 0, 0}, + {1202, 1, 21, 40, 70, 0, 0}, + {1202, 1, 41, 120, 80, 0, 0}, + {1202, 1, 121, 160, 90, 0, 0}, + {1202, 1, 161, 250, 100, 0, 0}, + {1202, 1, 251, 500, 100, 0, 0}, + {1202, 1, 501, 9999, 100, 0, 0}, + {1202, 2, 0, 100, 100, 0, 0}, + {1202, 2, 101, 200, 100, 0, 0}, + {1202, 2, 201, 500, 150, 0, 0}, + {1202, 2, 501, 9999, 150, 0, 0}, + // Mon Damage {ID, Block, StartFloor, EndFloor, Multiplier*100, Unk, Unk} + {1203, 1, 0, 5, 10, 0, 0}, + {1203, 1, 6, 10, 20, 0, 0}, + {1203, 1, 11, 30, 30, 0, 0}, + {1203, 1, 31, 60, 40, 0, 0}, + {1203, 1, 61, 120, 50, 0, 0}, + {1203, 1, 121, 130, 60, 0, 0}, + {1203, 1, 131, 140, 70, 0, 0}, + {1203, 1, 141, 150, 80, 0, 0}, + {1203, 1, 151, 160, 85, 0, 0}, + {1203, 1, 161, 200, 100, 0, 0}, + {1203, 1, 201, 500, 100, 0, 0}, + {1203, 1, 501, 9999, 100, 0, 0}, + {1203, 2, 0, 120, 70, 0, 0}, + {1203, 2, 121, 500, 120, 0, 0}, + {1203, 2, 501, 9999, 120, 0, 0}, + // Mon HP {ID, Block, StartFloor, EndFloor, Multiplier*100, Unk, Unk} + {1204, 1, 0, 5, 15, 0, 0}, + {1204, 1, 6, 10, 20, 0, 0}, + {1204, 1, 11, 15, 25, 0, 0}, + {1204, 1, 16, 20, 27, 0, 0}, + {1204, 1, 21, 25, 30, 0, 0}, + {1204, 1, 26, 30, 32, 0, 0}, + {1204, 1, 31, 40, 35, 0, 0}, + {1204, 1, 41, 50, 37, 0, 0}, + {1204, 1, 51, 60, 40, 0, 0}, + {1204, 1, 61, 70, 43, 0, 0}, + {1204, 1, 71, 80, 45, 0, 0}, + {1204, 1, 81, 90, 47, 0, 0}, + {1204, 1, 91, 100, 50, 0, 0}, + {1204, 1, 101, 110, 60, 0, 0}, + {1204, 1, 111, 120, 70, 0, 0}, + {1204, 1, 121, 130, 75, 0, 0}, + {1204, 1, 131, 140, 82, 0, 0}, + {1204, 1, 141, 160, 85, 0, 0}, + {1204, 1, 161, 200, 100, 0, 0}, + {1204, 1, 201, 500, 100, 0, 0}, + {1204, 1, 501, 9999, 100, 0, 0}, + {1204, 2, 0, 120, 70, 0, 0}, + {1204, 2, 121, 500, 120, 0, 0}, + {1204, 2, 501, 9999, 120, 0, 0}, + // Supply Items {ID, Block, Unk, ItemID, Quantity, Unk, Unk} + {4001, 1, 0, 0, 0, 0, 0}, + {4001, 2, 0, 10667, 5, 0, 1}, + {4001, 2, 0, 10667, 5, 0, 1}, + {4001, 2, 0, 10667, 5, 0, 1}, + {4001, 2, 0, 10667, 5, 0, 1}, + {4001, 2, 0, 10668, 2, 0, 1}, + {4001, 2, 0, 10668, 2, 0, 1}, + {4001, 2, 0, 10668, 2, 0, 1}, + {4001, 2, 0, 10668, 2, 0, 1}, + {4001, 2, 0, 10669, 1, 0, 1}, + {4001, 2, 0, 10669, 1, 0, 1}, + {4001, 2, 0, 10669, 1, 0, 1}, + {4001, 2, 0, 10669, 1, 0, 1}, + {4001, 2, 0, 10671, 3, 0, 1}, + {4001, 2, 0, 10671, 3, 0, 1}, + {4001, 2, 0, 10671, 3, 0, 1}, + {4001, 2, 0, 10671, 3, 0, 1}, + {4001, 2, 0, 10384, 1, 0, 1}, + {4001, 2, 0, 10384, 1, 0, 1}, + {4001, 2, 0, 10670, 2, 0, 1}, + {4001, 2, 0, 10670, 2, 0, 1}, + {4001, 2, 0, 10682, 2, 0, 1}, + {4001, 2, 0, 10683, 2, 0, 1}, + {4001, 2, 0, 10678, 1, 0, 1}, + {4001, 2, 0, 10678, 1, 0, 1}, + // Item Rewards {ID, Block, Unk, ItemID, Quantity?, Chance*100, Unk} + {4005, 1, 0, 11159, 1, 5000, 1}, + {4005, 1, 0, 11160, 1, 3350, 1}, + {4005, 1, 0, 11161, 1, 1500, 1}, + {4005, 1, 0, 11162, 1, 100, 1}, + {4005, 1, 0, 11163, 1, 50, 1}, + {4005, 2, 0, 11159, 2, 1800, 1}, + {4005, 2, 0, 11160, 2, 1200, 1}, + {4005, 2, 0, 11161, 2, 500, 1}, + {4005, 2, 0, 11162, 1, 50, 1}, + {4005, 2, 0, 11037, 1, 150, 1}, + {4005, 2, 0, 11038, 1, 150, 1}, + {4005, 2, 0, 11044, 1, 150, 1}, + {4005, 2, 0, 11057, 1, 150, 1}, + {4005, 2, 0, 11059, 1, 150, 1}, + {4005, 2, 0, 11079, 1, 150, 1}, + {4005, 2, 0, 11098, 1, 150, 1}, + {4005, 2, 0, 11104, 1, 150, 1}, + {4005, 2, 0, 11117, 1, 150, 1}, + {4005, 2, 0, 11128, 1, 150, 1}, + {4005, 2, 0, 11133, 1, 150, 1}, + {4005, 2, 0, 11137, 1, 150, 1}, + {4005, 2, 0, 11143, 1, 150, 1}, + {4005, 2, 0, 11132, 1, 150, 1}, + {4005, 2, 0, 11039, 1, 150, 1}, + {4005, 2, 0, 11040, 1, 150, 1}, + {4005, 2, 0, 11049, 1, 150, 1}, + {4005, 2, 0, 11061, 1, 150, 1}, + {4005, 2, 0, 11063, 1, 150, 1}, + {4005, 2, 0, 11077, 1, 150, 1}, + {4005, 2, 0, 11099, 1, 150, 1}, + {4005, 2, 0, 11105, 1, 150, 1}, + {4005, 2, 0, 11129, 1, 150, 1}, + {4005, 2, 0, 11130, 1, 150, 1}, + {4005, 2, 0, 11131, 1, 150, 1}, + {4005, 2, 0, 11139, 1, 150, 1}, + {4005, 2, 0, 11145, 1, 150, 1}, + {4005, 2, 0, 11096, 1, 150, 1}, + {4005, 2, 0, 11041, 1, 150, 1}, + {4005, 2, 0, 11047, 1, 150, 1}, + {4005, 2, 0, 11054, 1, 150, 1}, + {4005, 2, 0, 11065, 1, 150, 1}, + {4005, 2, 0, 11068, 1, 150, 1}, + {4005, 2, 0, 11075, 1, 150, 1}, + {4005, 2, 0, 11100, 1, 150, 1}, + {4005, 2, 0, 11106, 1, 150, 1}, + {4005, 2, 0, 11119, 1, 150, 1}, + {4005, 2, 0, 11135, 1, 150, 1}, + {4005, 2, 0, 11136, 1, 150, 1}, + {4005, 2, 0, 11138, 1, 150, 1}, + {4005, 2, 0, 11088, 1, 150, 1}, + {4005, 2, 0, 10370, 1, 150, 1}, + {4005, 2, 0, 10368, 1, 150, 1}, + {4006, 1, 0, 11159, 1, 5000, 1}, + {4006, 1, 0, 11160, 1, 3350, 1}, + {4006, 1, 0, 11161, 1, 1500, 1}, + {4006, 1, 0, 11162, 1, 100, 1}, + {4006, 1, 0, 11163, 1, 50, 1}, + {4006, 2, 0, 11159, 2, 1800, 1}, + {4006, 2, 0, 11160, 2, 1200, 1}, + {4006, 2, 0, 11161, 2, 500, 1}, + {4006, 2, 0, 11162, 1, 50, 1}, + {4006, 2, 0, 11037, 1, 150, 1}, + {4006, 2, 0, 11038, 1, 150, 1}, + {4006, 2, 0, 11044, 1, 150, 1}, + {4006, 2, 0, 11057, 1, 150, 1}, + {4006, 2, 0, 11059, 1, 150, 1}, + {4006, 2, 0, 11079, 1, 150, 1}, + {4006, 2, 0, 11098, 1, 150, 1}, + {4006, 2, 0, 11104, 1, 150, 1}, + {4006, 2, 0, 11117, 1, 150, 1}, + {4006, 2, 0, 11128, 1, 150, 1}, + {4006, 2, 0, 11133, 1, 150, 1}, + {4006, 2, 0, 11137, 1, 150, 1}, + {4006, 2, 0, 11143, 1, 150, 1}, + {4006, 2, 0, 11132, 1, 150, 1}, + {4006, 2, 0, 11039, 1, 150, 1}, + {4006, 2, 0, 11040, 1, 150, 1}, + {4006, 2, 0, 11049, 1, 150, 1}, + {4006, 2, 0, 11061, 1, 150, 1}, + {4006, 2, 0, 11063, 1, 150, 1}, + {4006, 2, 0, 11077, 1, 150, 1}, + {4006, 2, 0, 11099, 1, 150, 1}, + {4006, 2, 0, 11105, 1, 150, 1}, + {4006, 2, 0, 11129, 1, 150, 1}, + {4006, 2, 0, 11130, 1, 150, 1}, + {4006, 2, 0, 11131, 1, 150, 1}, + {4006, 2, 0, 11139, 1, 150, 1}, + {4006, 2, 0, 11145, 1, 150, 1}, + {4006, 2, 0, 11096, 1, 150, 1}, + {4006, 2, 0, 11041, 1, 150, 1}, + {4006, 2, 0, 11047, 1, 150, 1}, + {4006, 2, 0, 11054, 1, 150, 1}, + {4006, 2, 0, 11065, 1, 150, 1}, + {4006, 2, 0, 11068, 1, 150, 1}, + {4006, 2, 0, 11075, 1, 150, 1}, + {4006, 2, 0, 11100, 1, 150, 1}, + {4006, 2, 0, 11106, 1, 150, 1}, + {4006, 2, 0, 11119, 1, 150, 1}, + {4006, 2, 0, 11135, 1, 150, 1}, + {4006, 2, 0, 11136, 1, 150, 1}, + {4006, 2, 0, 11138, 1, 150, 1}, + {4006, 2, 0, 11088, 1, 150, 1}, + {4006, 2, 0, 10370, 1, 150, 1}, + {4006, 2, 0, 10368, 1, 150, 1}, + {4007, 1, 0, 11058, 1, 70, 1}, + {4007, 1, 0, 11060, 1, 70, 1}, + {4007, 1, 0, 11062, 1, 70, 1}, + {4007, 1, 0, 11064, 1, 70, 1}, + {4007, 1, 0, 11066, 1, 70, 1}, + {4007, 1, 0, 11118, 1, 70, 1}, + {4007, 1, 0, 11120, 1, 70, 1}, + {4007, 1, 0, 11110, 1, 70, 1}, + {4007, 1, 0, 11112, 1, 70, 1}, + {4007, 1, 0, 11114, 1, 70, 1}, + {4007, 1, 0, 11042, 1, 70, 1}, + {4007, 1, 0, 11043, 1, 70, 1}, + {4007, 1, 0, 11074, 1, 70, 1}, + {4007, 1, 0, 11140, 1, 70, 1}, + {4007, 1, 0, 11067, 1, 70, 1}, + {4007, 1, 0, 11048, 1, 70, 1}, + {4007, 1, 0, 11046, 1, 70, 1}, + {4007, 1, 0, 11103, 1, 70, 1}, + {4007, 1, 0, 11107, 1, 70, 1}, + {4007, 1, 0, 11108, 1, 70, 1}, + {4007, 1, 0, 11121, 1, 70, 1}, + {4007, 1, 0, 11134, 1, 70, 1}, + {4007, 1, 0, 11084, 1, 70, 1}, + {4007, 1, 0, 11085, 1, 70, 1}, + {4007, 1, 0, 11086, 1, 70, 1}, + {4007, 1, 0, 11087, 1, 70, 1}, + {4007, 1, 0, 11094, 1, 70, 1}, + {4007, 1, 0, 11095, 1, 70, 1}, + {4007, 1, 0, 10374, 1, 70, 1}, + {4007, 1, 0, 10375, 1, 70, 1}, + {4007, 1, 0, 10376, 1, 70, 1}, + {4007, 1, 0, 10377, 1, 70, 1}, + {4007, 1, 0, 10378, 1, 70, 1}, + {4007, 1, 0, 11069, 1, 45, 1}, + {4007, 1, 0, 11071, 1, 45, 1}, + {4007, 1, 0, 11073, 1, 45, 1}, + {4007, 1, 0, 11076, 1, 45, 1}, + {4007, 1, 0, 11078, 1, 45, 1}, + {4007, 1, 0, 11116, 1, 45, 1}, + {4007, 1, 0, 11123, 1, 45, 1}, + {4007, 1, 0, 11127, 1, 45, 1}, + {4007, 1, 0, 11142, 1, 45, 1}, + {4007, 1, 0, 11056, 1, 45, 1}, + {4007, 1, 0, 11090, 1, 45, 1}, + {4007, 1, 0, 11097, 1, 45, 1}, + {4007, 1, 0, 10367, 1, 45, 1}, + {4007, 1, 0, 10371, 1, 45, 1}, + {4007, 1, 0, 10373, 1, 45, 1}, + {4007, 1, 0, 11080, 1, 15, 1}, + {4007, 1, 0, 11081, 1, 15, 1}, + {4007, 1, 0, 11083, 1, 15, 1}, + {4007, 1, 0, 11125, 1, 15, 1}, + {4007, 1, 0, 11093, 1, 14, 1}, + {4007, 1, 0, 11053, 1, 10, 1}, + {4007, 1, 0, 11147, 1, 10, 1}, + {4007, 1, 0, 10372, 1, 5, 1}, + {4007, 1, 0, 10369, 1, 1, 1}, + {4007, 1, 0, 11163, 1, 150, 1}, + {4007, 1, 0, 11465, 1, 50, 1}, + {4007, 1, 0, 11466, 1, 25, 1}, + {4007, 1, 0, 11467, 1, 200, 1}, + {4007, 1, 0, 11468, 1, 400, 1}, + {4007, 1, 0, 11469, 1, 150, 1}, + {4007, 1, 0, 11037, 1, 92, 1}, + {4007, 1, 0, 11038, 1, 92, 1}, + {4007, 1, 0, 11044, 1, 92, 1}, + {4007, 1, 0, 11057, 1, 92, 1}, + {4007, 1, 0, 11059, 1, 92, 1}, + {4007, 1, 0, 11079, 1, 92, 1}, + {4007, 1, 0, 11098, 1, 92, 1}, + {4007, 1, 0, 11104, 1, 92, 1}, + {4007, 1, 0, 11117, 1, 92, 1}, + {4007, 1, 0, 11133, 1, 92, 1}, + {4007, 1, 0, 11137, 1, 92, 1}, + {4007, 1, 0, 11143, 1, 92, 1}, + {4007, 1, 0, 11132, 1, 92, 1}, + {4007, 1, 0, 11039, 1, 92, 1}, + {4007, 1, 0, 11040, 1, 92, 1}, + {4007, 1, 0, 11049, 1, 92, 1}, + {4007, 1, 0, 11061, 1, 92, 1}, + {4007, 1, 0, 11063, 1, 92, 1}, + {4007, 1, 0, 11077, 1, 92, 1}, + {4007, 1, 0, 11099, 1, 92, 1}, + {4007, 1, 0, 11105, 1, 92, 1}, + {4007, 1, 0, 11129, 1, 92, 1}, + {4007, 1, 0, 11130, 1, 92, 1}, + {4007, 1, 0, 11131, 1, 92, 1}, + {4007, 1, 0, 11139, 1, 92, 1}, + {4007, 1, 0, 11145, 1, 91, 1}, + {4007, 1, 0, 11096, 1, 91, 1}, + {4007, 1, 0, 11041, 1, 91, 1}, + {4007, 1, 0, 11047, 1, 91, 1}, + {4007, 1, 0, 11054, 1, 91, 1}, + {4007, 1, 0, 11065, 1, 91, 1}, + {4007, 1, 0, 11068, 1, 91, 1}, + {4007, 1, 0, 11075, 1, 91, 1}, + {4007, 1, 0, 11100, 1, 91, 1}, + {4007, 1, 0, 11106, 1, 91, 1}, + {4007, 1, 0, 11119, 1, 91, 1}, + {4007, 1, 0, 11135, 1, 91, 1}, + {4007, 1, 0, 11136, 1, 91, 1}, + {4007, 1, 0, 11138, 1, 91, 1}, + {4007, 1, 0, 11088, 1, 91, 1}, + {4007, 1, 0, 10370, 1, 91, 1}, + {4007, 1, 0, 10368, 1, 91, 1}, + {4007, 1, 0, 11045, 1, 91, 1}, + {4007, 1, 0, 11070, 1, 91, 1}, + {4007, 1, 0, 11101, 1, 91, 1}, + {4007, 1, 0, 11109, 1, 91, 1}, + {4007, 1, 0, 11122, 1, 91, 1}, + {4007, 1, 0, 11141, 1, 91, 1}, + {4007, 1, 0, 11051, 1, 91, 1}, + {4007, 1, 0, 11102, 1, 91, 1}, + {4007, 1, 0, 11124, 1, 91, 1}, + {4007, 1, 0, 11072, 1, 91, 1}, + {4007, 1, 0, 11082, 1, 91, 1}, + {4007, 1, 0, 11115, 1, 91, 1}, + {4007, 1, 0, 11144, 1, 91, 1}, + {4007, 1, 0, 11089, 1, 91, 1}, + {4007, 1, 0, 11091, 1, 91, 1}, + {4007, 1, 0, 11092, 1, 91, 1}, + {4007, 1, 0, 11050, 1, 91, 1}, + {4007, 1, 0, 11111, 1, 91, 1}, + {4007, 1, 0, 11113, 1, 91, 1}, + {4007, 1, 0, 11126, 1, 91, 1}, + {4007, 1, 0, 11055, 1, 91, 1}, + {4007, 1, 0, 11052, 1, 91, 1}, + {4007, 1, 0, 11146, 1, 91, 1}, + {4007, 2, 0, 11058, 1, 90, 1}, + {4007, 2, 0, 11060, 1, 90, 1}, + {4007, 2, 0, 11062, 1, 90, 1}, + {4007, 2, 0, 11064, 1, 90, 1}, + {4007, 2, 0, 11066, 1, 90, 1}, + {4007, 2, 0, 11118, 1, 90, 1}, + {4007, 2, 0, 11120, 1, 90, 1}, + {4007, 2, 0, 11110, 1, 90, 1}, + {4007, 2, 0, 11112, 1, 90, 1}, + {4007, 2, 0, 11114, 1, 90, 1}, + {4007, 2, 0, 11042, 1, 90, 1}, + {4007, 2, 0, 11043, 1, 90, 1}, + {4007, 2, 0, 11074, 1, 90, 1}, + {4007, 2, 0, 11140, 1, 90, 1}, + {4007, 2, 0, 11067, 1, 90, 1}, + {4007, 2, 0, 11048, 1, 90, 1}, + {4007, 2, 0, 11046, 1, 90, 1}, + {4007, 2, 0, 11103, 1, 90, 1}, + {4007, 2, 0, 11107, 1, 90, 1}, + {4007, 2, 0, 11108, 1, 90, 1}, + {4007, 2, 0, 11121, 1, 90, 1}, + {4007, 2, 0, 11134, 1, 90, 1}, + {4007, 2, 0, 11084, 1, 90, 1}, + {4007, 2, 0, 11085, 1, 90, 1}, + {4007, 2, 0, 11086, 1, 90, 1}, + {4007, 2, 0, 11087, 1, 90, 1}, + {4007, 2, 0, 11094, 1, 90, 1}, + {4007, 2, 0, 11095, 1, 90, 1}, + {4007, 2, 0, 10374, 1, 90, 1}, + {4007, 2, 0, 10375, 1, 90, 1}, + {4007, 2, 0, 10376, 1, 90, 1}, + {4007, 2, 0, 10377, 1, 90, 1}, + {4007, 2, 0, 10378, 1, 90, 1}, + {4007, 2, 0, 11069, 1, 80, 1}, + {4007, 2, 0, 11071, 1, 80, 1}, + {4007, 2, 0, 11073, 1, 80, 1}, + {4007, 2, 0, 11076, 1, 80, 1}, + {4007, 2, 0, 11078, 1, 80, 1}, + {4007, 2, 0, 11116, 1, 80, 1}, + {4007, 2, 0, 11123, 1, 80, 1}, + {4007, 2, 0, 11127, 1, 80, 1}, + {4007, 2, 0, 11142, 1, 80, 1}, + {4007, 2, 0, 11056, 1, 80, 1}, + {4007, 2, 0, 11090, 1, 80, 1}, + {4007, 2, 0, 11097, 1, 80, 1}, + {4007, 2, 0, 10367, 1, 80, 1}, + {4007, 2, 0, 10371, 1, 80, 1}, + {4007, 2, 0, 10373, 1, 80, 1}, + {4007, 2, 0, 11080, 1, 22, 1}, + {4007, 2, 0, 11081, 1, 22, 1}, + {4007, 2, 0, 11083, 1, 22, 1}, + {4007, 2, 0, 11125, 1, 22, 1}, + {4007, 2, 0, 11093, 1, 22, 1}, + {4007, 2, 0, 11053, 1, 15, 1}, + {4007, 2, 0, 11147, 1, 15, 1}, + {4007, 2, 0, 10372, 1, 8, 1}, + {4007, 2, 0, 10369, 1, 2, 1}, + {4007, 2, 0, 11159, 3, 1220, 1}, + {4007, 2, 0, 11160, 3, 650, 1}, + {4007, 2, 0, 11161, 3, 160, 1}, + {4007, 2, 0, 11661, 1, 800, 1}, + {4007, 2, 0, 11662, 1, 800, 1}, + {4007, 2, 0, 11163, 1, 500, 1}, + {4007, 2, 0, 11162, 1, 550, 1}, + {4007, 2, 0, 11465, 1, 50, 1}, + {4007, 2, 0, 11466, 1, 25, 1}, + {4007, 2, 0, 11467, 1, 250, 1}, + {4007, 2, 0, 11468, 1, 500, 1}, + {4007, 2, 0, 11469, 1, 175, 1}, + // Probably treasure chest rewards + {4202, 1, 0, 11163, 1, 6000, 1}, + {4202, 1, 0, 11465, 1, 200, 1}, + {4202, 1, 0, 11466, 1, 100, 1}, + {4202, 1, 0, 11467, 1, 1000, 1}, + {4202, 1, 0, 11468, 1, 2000, 1}, + {4202, 1, 0, 11469, 1, 700, 1}, + {4202, 2, 0, 11661, 1, 800, 1}, + {4202, 2, 0, 11662, 1, 800, 1}, + {4202, 2, 0, 11163, 1, 400, 1}, + {4202, 2, 0, 11465, 1, 400, 1}, + {4202, 2, 0, 11466, 1, 200, 1}, + {4202, 2, 0, 11467, 1, 2000, 1}, + {4202, 2, 0, 11468, 1, 4000, 1}, + {4202, 2, 0, 11469, 1, 1400, 1}, + } + default: + if pkt.Unk2 < 1000 { + s.logger.Info("PaperData request for unknown type", zap.Uint32("Unk2", pkt.Unk2)) + } + } + + if pkt.Unk2 > 1000 { + _, ok := paperGiftData[pkt.Unk2] + if ok { + paperGift = paperGiftData[pkt.Unk2] + } else { + s.logger.Info("PaperGift request for unknown type", zap.Uint32("Unk2", pkt.Unk2)) + } + for _, gift := range paperGift { + bf := byteframe.NewByteFrame() + bf.WriteUint16(gift.Unk0) + bf.WriteUint8(gift.Unk1) + bf.WriteUint8(gift.Unk2) + bf.WriteUint16(gift.Unk3) + data = append(data, bf) + } + doAckEarthSucceed(s, pkt.AckHandle, data) + } else if pkt.Unk2 == 0 { + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(len(paperMissions.Timetables))) + bf.WriteUint16(uint16(len(paperMissions.Data))) + for _, timetable := range paperMissions.Timetables { + bf.WriteUint32(uint32(timetable.Start.Unix())) + bf.WriteUint32(uint32(timetable.End.Unix())) + } + for _, mdata := range paperMissions.Data { + bf.WriteUint8(mdata.Unk0) + bf.WriteUint8(mdata.Unk1) + bf.WriteInt16(mdata.Unk2) + bf.WriteUint16(mdata.Reward1ID) + bf.WriteUint8(mdata.Reward1Quantity) + bf.WriteUint16(mdata.Reward2ID) + bf.WriteUint8(mdata.Reward2Quantity) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } else { - data = []byte{0x00, 0x00, 0x00, 0x00} - s.logger.Info("GET_PAPER request for unknown type") + for _, pdata := range paperData { + bf := byteframe.NewByteFrame() + bf.WriteUint16(pdata.Unk0) + bf.WriteInt16(pdata.Unk1) + bf.WriteInt16(pdata.Unk2) + bf.WriteInt16(pdata.Unk3) + bf.WriteInt16(pdata.Unk4) + bf.WriteInt16(pdata.Unk5) + bf.WriteInt16(pdata.Unk6) + data = append(data, bf) + } + doAckEarthSucceed(s, pkt.AckHandle, data) } - if err != nil { - panic(err) - } - doAckBufSucceed(s, pkt.AckHandle, data) } func handleMsgSysAuthData(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_diva.go b/server/channelserver/handlers_diva.go index 0daabe70c..1867bfacd 100644 --- a/server/channelserver/handlers_diva.go +++ b/server/channelserver/handlers_diva.go @@ -3,6 +3,7 @@ package channelserver import ( "encoding/hex" "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "time" "erupe-ce/common/byteframe" @@ -71,7 +72,11 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) { var timestamps []uint32 if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DivaEvent >= 0 { if s.server.erupeConfig.DevModeOptions.DivaEvent == 0 { - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 36)) + if s.server.erupeConfig.RealClientMode <= _config.Z1 { + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 32)) + } else { + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 36)) + } return } timestamps = generateDivaTimestamps(s, uint32(s.server.erupeConfig.DevModeOptions.DivaEvent), true) @@ -79,9 +84,11 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) { timestamps = generateDivaTimestamps(s, start, false) } - bf.WriteUint32(id) - for _, timestamp := range timestamps { - bf.WriteUint32(timestamp) + if s.server.erupeConfig.RealClientMode <= _config.Z1 { + bf.WriteUint32(id) + } + for i := range timestamps { + bf.WriteUint32(timestamps[i]) } bf.WriteUint16(0x19) // Unk 00011001 diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index bba4c1065..7797bd6fc 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -2,6 +2,7 @@ package channelserver import ( "erupe-ce/common/token" + _config "erupe-ce/config" "math" "time" @@ -47,9 +48,41 @@ func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) { }) } +type Event struct { + Unk0 uint16 + Unk1 uint16 + Unk2 uint16 + Unk3 uint16 + Unk4 uint16 + Unk5 uint32 + Unk6 uint32 + Unk7 []uint16 +} + func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateEvent) - stubEnumerateNoResults(s, pkt.AckHandle) + bf := byteframe.NewByteFrame() + + events := []Event{} + + bf.WriteUint8(uint8(len(events))) + for _, event := range events { + bf.WriteUint16(event.Unk0) + bf.WriteUint16(event.Unk1) + bf.WriteUint16(event.Unk2) + bf.WriteUint16(event.Unk3) + bf.WriteUint16(event.Unk4) + bf.WriteUint32(event.Unk5) + bf.WriteUint32(event.Unk6) + if event.Unk0 == 2 { + bf.WriteUint8(uint8(len(event.Unk7))) + for _, u := range event.Unk7 { + bf.WriteUint16(u) + } + } + } + + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } type activeFeature struct { @@ -90,14 +123,24 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) { } func generateFeatureWeapons(count int) activeFeature { - if count > 14 { - count = 14 + max := 14 + if _config.ErupeConfig.RealClientMode < _config.ZZ { + max = 13 + } + if _config.ErupeConfig.RealClientMode < _config.G10 { + max = 12 + } + if _config.ErupeConfig.RealClientMode < _config.GG { + max = 11 + } + if count > max { + count = max } nums := make([]int, 0) var result int for len(nums) < count { rng := token.RNG() - num := rng.Intn(14) + num := rng.Intn(max) exist := false for _, v := range nums { if v == num { diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 155cee3d8..0f590b5d9 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -1,7 +1,6 @@ package channelserver import ( - "encoding/hex" "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/common/token" @@ -140,13 +139,26 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 { return timestamps } -type Trial struct { +type FestaTrial struct { ID uint32 `db:"id"` - Objective uint8 `db:"objective"` + Objective uint16 `db:"objective"` GoalID uint32 `db:"goal_id"` TimesReq uint16 `db:"times_req"` Locale uint16 `db:"locale_req"` Reward uint16 `db:"reward"` + Monopoly uint16 + Unk uint16 +} + +type FestaReward struct { + Unk0 uint8 + Unk1 uint8 + ItemType uint16 + Quantity uint16 + ItemID uint16 + Unk5 uint16 + Unk6 uint16 + Unk7 uint8 } func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { @@ -190,36 +202,71 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(blueSouls) bf.WriteUint32(redSouls) + var trials []FestaTrial + var trial FestaTrial rows, _ = s.server.db.Queryx("SELECT * FROM festa_trials") - trialData := byteframe.NewByteFrame() - var count uint16 for rows.Next() { - trial := &Trial{} err := rows.StructScan(&trial) if err != nil { continue } - count++ - trialData.WriteUint32(trial.ID) - trialData.WriteUint8(0) // Unk - trialData.WriteUint8(trial.Objective) - trialData.WriteUint32(trial.GoalID) - trialData.WriteUint16(trial.TimesReq) - trialData.WriteUint16(trial.Locale) - trialData.WriteUint16(trial.Reward) - trialData.WriteUint8(0xFF) // Unk - trialData.WriteUint8(0xFF) // MonopolyState - trialData.WriteUint16(0) // Unk + trials = append(trials, trial) + } + bf.WriteUint16(uint16(len(trials))) + for _, trial := range trials { + bf.WriteUint32(trial.ID) + bf.WriteUint16(trial.Objective) + bf.WriteUint32(trial.GoalID) + bf.WriteUint16(trial.TimesReq) + bf.WriteUint16(trial.Locale) + bf.WriteUint16(trial.Reward) + trial.Monopoly = 0xFFFF // NYI + bf.WriteUint16(trial.Monopoly) + bf.WriteUint16(trial.Unk) } - bf.WriteUint16(count) - bf.WriteBytes(trialData.Data()) - // Static bonus rewards - rewards, _ := hex.DecodeString("001901000007015E05F000000000000100000703E81B6300000000010100000C03E8000000000000000100000D0000000000000000000100000100000000000000000002000007015E05F000000000000200000703E81B6300000000010200000C03E8000000000000000200000D0000000000000000000200000400000000000000000003000007015E05F000000000000300000703E81B6300000000010300000C03E8000000000000000300000D0000000000000000000300000100000000000000000004000007015E05F000000000000400000703E81B6300000000010400000C03E8000000000000000400000D0000000000000000000400000400000000000000000005000007015E05F000000000000500000703E81B6300000000010500000C03E8000000000000000500000D00000000000000000005000001000000000000000000") - bf.WriteBytes(rewards) + // The Winner and Loser Armor IDs are missing + rewards := []FestaReward{ + {1, 0, 7, 350, 1520, 0, 0, 0}, + {1, 0, 7, 1000, 7011, 0, 0, 1}, + {1, 0, 12, 1000, 0, 0, 0, 0}, + {1, 0, 13, 0, 0, 0, 0, 0}, + //{1, 0, 1, 0, 0, 0, 0, 0}, + {2, 0, 7, 350, 1520, 0, 0, 0}, + {2, 0, 7, 1000, 7011, 0, 0, 1}, + {2, 0, 12, 1000, 0, 0, 0, 0}, + {2, 0, 13, 0, 0, 0, 0, 0}, + //{2, 0, 4, 0, 0, 0, 0, 0}, + {3, 0, 7, 350, 1520, 0, 0, 0}, + {3, 0, 7, 1000, 7011, 0, 0, 1}, + {3, 0, 12, 1000, 0, 0, 0, 0}, + {3, 0, 13, 0, 0, 0, 0, 0}, + //{3, 0, 1, 0, 0, 0, 0, 0}, + {4, 0, 7, 350, 1520, 0, 0, 0}, + {4, 0, 7, 1000, 7011, 0, 0, 1}, + {4, 0, 12, 1000, 0, 0, 0, 0}, + {4, 0, 13, 0, 0, 0, 0, 0}, + //{4, 0, 4, 0, 0, 0, 0, 0}, + {5, 0, 7, 350, 1520, 0, 0, 0}, + {5, 0, 7, 1000, 7011, 0, 0, 1}, + {5, 0, 12, 1000, 0, 0, 0, 0}, + {5, 0, 13, 0, 0, 0, 0, 0}, + //{5, 0, 1, 0, 0, 0, 0, 0}, + } + bf.WriteUint16(uint16(len(rewards))) + for _, reward := range rewards { + bf.WriteUint8(reward.Unk0) + bf.WriteUint8(reward.Unk1) + bf.WriteUint16(reward.ItemType) + bf.WriteUint16(reward.Quantity) + bf.WriteUint16(reward.ItemID) + bf.WriteUint16(reward.Unk5) + bf.WriteUint16(reward.Unk6) + bf.WriteUint8(reward.Unk7) + } - bf.WriteUint16(0x0001) - bf.WriteUint32(0xD4C001F4) + bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MaximumFP) + bf.WriteUint16(500) categoryWinners := uint16(0) // NYI bf.WriteUint16(categoryWinners) @@ -239,8 +286,18 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, "", true) // Guild Name } - d, _ := hex.DecodeString("000000000000000100001388000007D0000003E800000064012C00C8009600640032") - bf.WriteBytes(d) + // Unknown values + bf.WriteUint32(1) + bf.WriteUint32(5000) + bf.WriteUint32(2000) + bf.WriteUint32(1000) + bf.WriteUint32(100) + bf.WriteUint16(300) + bf.WriteUint16(200) + bf.WriteUint16(150) + bf.WriteUint16(100) + bf.WriteUint16(50) + ps.Uint16(bf, "", false) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 09520d8c4..5fdd2dac1 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "encoding/json" "errors" + _config "erupe-ce/config" "fmt" "math" "sort" @@ -62,7 +63,6 @@ type Guild struct { Recruiting bool `db:"recruiting"` FestivalColour FestivalColour `db:"festival_colour"` Souls uint32 `db:"souls"` - Rank uint16 `db:"rank"` AllianceID uint32 `db:"alliance_id"` Icon *GuildIcon `db:"icon"` @@ -115,6 +115,39 @@ func (gi *GuildIcon) Value() (valuer driver.Value, err error) { return json.Marshal(gi) } +func (g *Guild) Rank() uint16 { + rpMap := []uint32{ + 24, 48, 96, 144, 192, 240, 288, 360, 432, + 504, 600, 696, 792, 888, 984, 1080, 1200, + } + if _config.ErupeConfig.RealClientMode <= _config.Z2 { + rpMap = []uint32{ + 3500, 6000, 8500, 11000, 13500, 16000, 20000, 24000, 28000, + 33000, 38000, 43000, 48000, 55000, 70000, 90000, 120000, + } + } + for i, u := range rpMap { + if g.RankRP < u { + if _config.ErupeConfig.RealClientMode <= _config.S6 && i >= 12 { + return 12 + } else if _config.ErupeConfig.RealClientMode <= _config.F5 && i >= 13 { + return 13 + } else if _config.ErupeConfig.RealClientMode <= _config.G32 && i >= 14 { + return 14 + } + return uint16(i) + } + } + if _config.ErupeConfig.RealClientMode <= _config.S6 { + return 12 + } else if _config.ErupeConfig.RealClientMode <= _config.F5 { + return 13 + } else if _config.ErupeConfig.RealClientMode <= _config.G32 { + return 14 + } + return 17 +} + const guildInfoSelectQuery = ` SELECT g.id, @@ -137,14 +170,6 @@ SELECT 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, - CASE - WHEN rank_rp <= 48 THEN rank_rp/24 - WHEN rank_rp <= 288 THEN rank_rp/48+1 - WHEN rank_rp <= 504 THEN rank_rp/72+3 - WHEN rank_rp <= 1080 THEN (rank_rp-24)/96+5 - WHEN rank_rp < 1200 THEN 16 - ELSE 17 - END rank, COALESCE(( SELECT id FROM guild_alliances ga WHERE ga.parent_id = g.id OR @@ -615,13 +640,7 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfOperateGuild) guild, err := GetGuildInfoByID(s, pkt.GuildID) - - if err != nil { - return - } - characterGuildInfo, err := GetCharacterGuildData(s, s.charID) - if err != nil { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return @@ -630,22 +649,19 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() switch pkt.Action { - case mhfpacket.OPERATE_GUILD_DISBAND: + case mhfpacket.OperateGuildDisband: + response := 1 if guild.LeaderCharID != s.charID { s.logger.Warn(fmt.Sprintf("character '%d' is attempting to manage guild '%d' without permission", s.charID, guild.ID)) - return + response = 0 + } else { + err = guild.Disband(s) + if err != nil { + response = 0 + } } - - err = guild.Disband(s) - response := 0x01 - - if err != nil { - // All successful acks return 0x01, assuming 0x00 is failure - response = 0x00 - } - bf.WriteUint32(uint32(response)) - case mhfpacket.OPERATE_GUILD_RESIGN: + case mhfpacket.OperateGuildResign: guildMembers, err := GetGuildMembers(s, guild.ID, false) if err == nil { sort.Slice(guildMembers[:], func(i, j int) bool { @@ -664,25 +680,22 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { } guild.Save(s) } - case mhfpacket.OPERATE_GUILD_APPLY: + case mhfpacket.OperateGuildApply: err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil) - if err == nil { bf.WriteUint32(guild.LeaderCharID) + } else { + bf.WriteUint32(0) } - case mhfpacket.OPERATE_GUILD_LEAVE: - var err error - + case mhfpacket.OperateGuildLeave: if characterGuildInfo.IsApplicant { err = guild.RejectApplication(s, s.charID) } else { err = guild.RemoveCharacter(s, s.charID) } - - response := 0x01 + response := 1 if err != nil { - // All successful acks return 0x01, assuming 0x00 is failure - response = 0x00 + response = 0 } else { mail := Mail{ RecipientID: s.charID, @@ -692,26 +705,25 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { } mail.Send(s, nil) } - bf.WriteUint32(uint32(response)) - case mhfpacket.OPERATE_GUILD_DONATE_RANK: + case mhfpacket.OperateGuildDonateRank: bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, false)) - case mhfpacket.OPERATE_GUILD_SET_APPLICATION_DENY: + case mhfpacket.OperateGuildSetApplicationDeny: s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID) - case mhfpacket.OPERATE_GUILD_SET_APPLICATION_ALLOW: + case mhfpacket.OperateGuildSetApplicationAllow: s.server.db.Exec("UPDATE guilds SET recruiting=true WHERE id=$1", guild.ID) - case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE: + case mhfpacket.OperateGuildSetAvoidLeadershipTrue: handleAvoidLeadershipUpdate(s, pkt, true) - case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE: + case mhfpacket.OperateGuildSetAvoidLeadershipFalse: handleAvoidLeadershipUpdate(s, pkt, false) - case mhfpacket.OPERATE_GUILD_UPDATE_COMMENT: + case mhfpacket.OperateGuildUpdateComment: if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes()) guild.Save(s) - case mhfpacket.OPERATE_GUILD_UPDATE_MOTTO: + case mhfpacket.OperateGuildUpdateMotto: if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return @@ -720,27 +732,29 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { guild.SubMotto = pkt.Data1.ReadUint8() guild.MainMotto = pkt.Data1.ReadUint8() guild.Save(s) - case mhfpacket.OPERATE_GUILD_RENAME_PUGI_1: + case mhfpacket.OperateGuildRenamePugi1: handleRenamePugi(s, pkt.Data2, guild, 1) - case mhfpacket.OPERATE_GUILD_RENAME_PUGI_2: + case mhfpacket.OperateGuildRenamePugi2: handleRenamePugi(s, pkt.Data2, guild, 2) - case mhfpacket.OPERATE_GUILD_RENAME_PUGI_3: + case mhfpacket.OperateGuildRenamePugi3: handleRenamePugi(s, pkt.Data2, guild, 3) - case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_1: + case mhfpacket.OperateGuildChangePugi1: handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 1) - case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_2: + case mhfpacket.OperateGuildChangePugi2: handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 2) - case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_3: + case mhfpacket.OperateGuildChangePugi3: handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 3) - case mhfpacket.OPERATE_GUILD_UNLOCK_OUTFIT: + case mhfpacket.OperateGuildUnlockOutfit: // 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: + case mhfpacket.OperateGuildDonateRoom: + // TODO: Where does this go? + case mhfpacket.OperateGuildDonateEvent: quantity := uint16(pkt.Data1.ReadUint32()) bf.WriteBytes(handleDonateRP(s, quantity, guild, true)) // TODO: Move this value onto rp_yesterday and reset to 0... daily? s.server.db.Exec(`UPDATE guild_characters SET rp_today=rp_today+$1 WHERE character_id=$2`, quantity, s.charID) - case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE: + case mhfpacket.OperateGuildEventExchange: 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) @@ -922,14 +936,19 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(guild.ID) bf.WriteUint32(guild.LeaderCharID) - bf.WriteUint16(guild.Rank) + bf.WriteUint16(guild.Rank()) bf.WriteUint16(guild.MemberCount) bf.WriteUint8(guild.MainMotto) bf.WriteUint8(guild.SubMotto) // Unk appears to be static - bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + bf.WriteUint8(0) + bf.WriteUint8(0) + bf.WriteUint8(0) + bf.WriteUint8(0) + bf.WriteUint8(0) + bf.WriteUint8(0) bf.WriteBool(!guild.Recruiting) @@ -952,28 +971,39 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint8(FestivalColourCodes[guild.FestivalColour]) bf.WriteUint32(guild.RankRP) bf.WriteBytes(guildLeaderName) - bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00}) // Unk - bf.WriteBool(false) // isReturnGuild - bf.WriteBool(false) // earnedSpecialHall - bf.WriteBytes([]byte{0x02, 0x02}) // Unk - bf.WriteUint32(guild.EventRP) + bf.WriteUint32(0) // Unk + bf.WriteBool(false) // isReturnGuild + bf.WriteBool(false) // earnedSpecialHall + bf.WriteUint8(2) + bf.WriteUint8(2) + bf.WriteUint32(guild.EventRP) // Skipped if last byte is <2? ps.Uint8(bf, guild.PugiName1, true) ps.Uint8(bf, guild.PugiName2, true) ps.Uint8(bf, guild.PugiName3, true) bf.WriteUint8(guild.PugiOutfit1) bf.WriteUint8(guild.PugiOutfit2) bf.WriteUint8(guild.PugiOutfit3) - bf.WriteUint8(guild.PugiOutfit1) - bf.WriteUint8(guild.PugiOutfit2) - bf.WriteUint8(guild.PugiOutfit3) + if s.server.erupeConfig.RealClientMode >= _config.Z1 { + 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 + if guild.Rank() >= 3 { + bf.WriteUint8(40) + } else if guild.Rank() >= 7 { + bf.WriteUint8(50) + } else if guild.Rank() >= 10 { + bf.WriteUint8(60) + } else { + bf.WriteUint8(30) + } - bf.WriteBytes([]byte{ - 0x00, 0x00, 0xD6, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }) + bf.WriteUint32(55000) + bf.WriteUint32(0) + bf.WriteUint16(0) // Changing Room RP + bf.WriteUint16(0) if guild.AllianceID > 0 { alliance, err := GetAllianceData(s, guild.AllianceID) @@ -983,7 +1013,8 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(alliance.ID) bf.WriteUint32(uint32(alliance.CreatedAt.Unix())) bf.WriteUint16(alliance.TotalMembers) - bf.WriteUint16(0) // Unk0 + bf.WriteUint8(0) + bf.WriteUint8(0) ps.Uint16(bf, alliance.Name, true) if alliance.SubGuild1ID > 0 { if alliance.SubGuild2ID > 0 { @@ -1001,7 +1032,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { } else { bf.WriteUint16(0) } - bf.WriteUint16(alliance.ParentGuild.Rank) + bf.WriteUint16(alliance.ParentGuild.Rank()) bf.WriteUint16(alliance.ParentGuild.MemberCount) ps.Uint16(bf, alliance.ParentGuild.Name, true) ps.Uint16(bf, alliance.ParentGuild.LeaderName, true) @@ -1013,7 +1044,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { } else { bf.WriteUint16(0) } - bf.WriteUint16(alliance.SubGuild1.Rank) + bf.WriteUint16(alliance.SubGuild1.Rank()) bf.WriteUint16(alliance.SubGuild1.MemberCount) ps.Uint16(bf, alliance.SubGuild1.Name, true) ps.Uint16(bf, alliance.SubGuild1.LeaderName, true) @@ -1026,7 +1057,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { } else { bf.WriteUint16(0) } - bf.WriteUint16(alliance.SubGuild2.Rank) + bf.WriteUint16(alliance.SubGuild2.Rank()) bf.WriteUint16(alliance.SubGuild2.MemberCount) ps.Uint16(bf, alliance.SubGuild2.Name, true) ps.Uint16(bf, alliance.SubGuild2.LeaderName, true) @@ -1043,29 +1074,46 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(uint16(len(applicants))) for _, applicant := range applicants { bf.WriteUint32(applicant.CharID) - bf.WriteUint16(0) - bf.WriteUint16(0) + bf.WriteUint32(0) bf.WriteUint16(applicant.HRP) bf.WriteUint16(applicant.GR) ps.Uint8(bf, applicant.Name, true) } } - bf.WriteUint16(0x0000) // lenAllianceApplications + type UnkGuildInfo struct { + Unk0 uint8 + Unk1 uint8 + Unk2 uint8 + } + unkGuildInfo := []UnkGuildInfo{} + bf.WriteUint8(uint8(len(unkGuildInfo))) + for _, info := range unkGuildInfo { + bf.WriteUint8(info.Unk0) + bf.WriteUint8(info.Unk1) + bf.WriteUint8(info.Unk2) + } - /* - alliance application format - uint16 numapplicants (above) - - uint32 guild id - uint32 guild leader id (for mail) - uint32 unk (always null in pcap) - uint16 member count - uint16 len guild name - string nullterm guild name - uint16 len guild leader name - string nullterm guild leader name - */ + type AllianceInvite struct { + GuildID uint32 + LeaderID uint32 + Unk0 uint16 + Unk1 uint16 + Members uint16 + GuildName string + LeaderName string + } + allianceInvites := []AllianceInvite{} + bf.WriteUint8(uint8(len(allianceInvites))) + for _, invite := range allianceInvites { + bf.WriteUint32(invite.GuildID) + bf.WriteUint32(invite.LeaderID) + bf.WriteUint16(invite.Unk0) + bf.WriteUint16(invite.Unk1) + bf.WriteUint16(invite.Members) + ps.Uint16(bf, invite.GuildName, true) + ps.Uint16(bf, invite.LeaderName, true) + } if guild.Icon != nil { bf.WriteUint8(uint8(len(guild.Icon.Parts))) @@ -1083,7 +1131,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(p.PosY) } } else { - bf.WriteUint8(0x00) + bf.WriteUint8(0) } bf.WriteUint8(0) // Unk @@ -1285,7 +1333,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(guild.LeaderCharID) bf.WriteUint16(guild.MemberCount) bf.WriteUint16(0x0000) // Unk - bf.WriteUint16(guild.Rank) + bf.WriteUint16(guild.Rank()) bf.WriteUint32(uint32(guild.CreatedAt.Unix())) ps.Uint8(bf, guild.Name, true) ps.Uint8(bf, guild.LeaderName, true) @@ -1347,7 +1395,7 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) { if guild != nil { isApplicant, _ := guild.HasApplicationForCharID(s, s.charID) if isApplicant { - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2)) return } } @@ -1389,8 +1437,15 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) { for _, member := range guildMembers { bf.WriteUint32(member.CharID) bf.WriteUint16(member.HRP) - bf.WriteUint16(member.GR) - bf.WriteUint16(member.WeaponID) + if s.server.erupeConfig.RealClientMode > _config.G7 { + bf.WriteUint16(member.GR) + } + if s.server.erupeConfig.RealClientMode < _config.ZZ { + // Magnet Spike crash workaround + bf.WriteUint16(0) + } else { + bf.WriteUint16(member.WeaponID) + } if member.WeaponType == 1 || member.WeaponType == 5 || member.WeaponType == 10 { // If weapon is ranged bf.WriteUint8(7) } else { @@ -1450,7 +1505,6 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight) guild, err := GetGuildInfoByCharacterId(s, s.charID) - if guild == nil && s.prevGuildID != 0 { guild, err = GetGuildInfoByID(s, s.prevGuildID) s.prevGuildID = 0 @@ -1460,31 +1514,14 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) { } } - if err != nil { - s.logger.Warn("failed to respond to manage rights message") - return - } else if guild == nil { - bf := byteframe.NewByteFrame() - bf.WriteUint16(0x00) // Unk - bf.WriteUint16(0x00) // Member count - - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - return - } - bf := byteframe.NewByteFrame() - - bf.WriteUint16(0x00) // Unk - bf.WriteUint16(guild.MemberCount) - + bf.WriteUint32(uint32(guild.MemberCount)) members, _ := GetGuildMembers(s, guild.ID, false) - for _, member := range members { bf.WriteUint32(member.CharID) bf.WriteBool(member.Recruiter) bf.WriteBytes(make([]byte, 3)) } - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } diff --git a/server/channelserver/handlers_guild_alliance.go b/server/channelserver/handlers_guild_alliance.go index fbb285e0a..f27d67026 100644 --- a/server/channelserver/handlers_guild_alliance.go +++ b/server/channelserver/handlers_guild_alliance.go @@ -209,14 +209,14 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) { } bf.WriteUint32(alliance.ParentGuildID) bf.WriteUint32(alliance.ParentGuild.LeaderCharID) - bf.WriteUint16(alliance.ParentGuild.Rank) + 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.Rank()) bf.WriteUint16(alliance.SubGuild1.MemberCount) ps.Uint16(bf, alliance.SubGuild1.Name, true) ps.Uint16(bf, alliance.SubGuild1.LeaderName, true) @@ -224,7 +224,7 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) { if alliance.SubGuild2ID > 0 { bf.WriteUint32(alliance.SubGuild2ID) bf.WriteUint32(alliance.SubGuild2.LeaderCharID) - bf.WriteUint16(alliance.SubGuild2.Rank) + bf.WriteUint16(alliance.SubGuild2.Rank()) bf.WriteUint16(alliance.SubGuild2.MemberCount) ps.Uint16(bf, alliance.SubGuild2.Name, true) ps.Uint16(bf, alliance.SubGuild2.LeaderName, true) diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index ab150f180..52cdb4fa9 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -4,6 +4,7 @@ import ( "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "erupe-ce/network/mhfpacket" "fmt" "go.uber.org/zap" @@ -249,6 +250,9 @@ func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) { s.logger.Error("Failed to load decomyset", zap.Error(err)) } if len(data) == 0 { + if s.server.erupeConfig.RealClientMode <= _config.G7 { + data = []byte{0x00, 0x00} + } data = []byte{0x01, 0x00} } doAckBufSucceed(s, pkt.AckHandle, data) diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index 251bc107b..810786751 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -3,6 +3,7 @@ package channelserver import ( "erupe-ce/common/byteframe" "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "erupe-ce/network/mhfpacket" "erupe-ce/server/channelserver/compression/deltacomp" "erupe-ce/server/channelserver/compression/nullcomp" @@ -56,11 +57,15 @@ func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi) + naviLength := 552 + if s.server.erupeConfig.RealClientMode <= _config.G7 { + naviLength = 280 + } var data []byte err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data) if len(data) == 0 { s.logger.Error("Failed to load hunternavi", zap.Error(err)) - data = make([]byte, 0x226) + data = make([]byte, naviLength) } doAckBufSucceed(s, pkt.AckHandle, data) } @@ -68,6 +73,10 @@ func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi) if pkt.IsDataDiff { + naviLength := 552 + if s.server.erupeConfig.RealClientMode <= _config.G7 { + naviLength = 280 + } var data []byte // Load existing save err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data) @@ -78,7 +87,7 @@ func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) { // Check if we actually had any hunternavi data, using a blank buffer if not. // This is requried as the client will try to send a diff after character creation without a prior MsgMhfSaveHunterNavi packet. if len(data) == 0 { - data = make([]byte, 0x226) + data = make([]byte, naviLength) } // Perform diff and compress it to write back to db @@ -222,8 +231,8 @@ func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfContractMercenary) switch pkt.Op { - case 0: - s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, s.charID) + case 0: // Form loan + s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, pkt.CID) case 1: // Cancel lend s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.charID) case 2: // Cancel loan diff --git a/server/channelserver/handlers_object.go b/server/channelserver/handlers_object.go index 8984c21bf..520b6fef7 100644 --- a/server/channelserver/handlers_object.go +++ b/server/channelserver/handlers_object.go @@ -78,7 +78,8 @@ func handleMsgSysRotateObject(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgSysSetObjectBinary) + _ = p.(*mhfpacket.MsgSysSetObjectBinary) + /* This causes issues with PS3 as this actually sends with endiness! for _, session := range s.server.sessions { if session.charID == s.charID { s.server.userBinaryPartsLock.Lock() @@ -91,6 +92,7 @@ func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) { s.server.BroadcastMHF(msg, s) } } + */ } func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 9caef6dbf..f295b37fb 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -1,15 +1,14 @@ package channelserver import ( - "encoding/hex" + "erupe-ce/common/byteframe" + "erupe-ce/network/mhfpacket" "fmt" + "go.uber.org/zap" "io" "os" "path/filepath" - - "erupe-ce/common/byteframe" - "erupe-ce/network/mhfpacket" - "go.uber.org/zap" + "time" ) func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { @@ -85,7 +84,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { var totalCount, returnedCount uint16 bf := byteframe.NewByteFrame() bf.WriteUint16(0) - err := filepath.Walk(fmt.Sprintf("%s/events/", s.server.erupeConfig.BinPath), func(path string, info os.FileInfo, err error) error { + filepath.Walk(fmt.Sprintf("%s/events/", s.server.erupeConfig.BinPath), func(path string, info os.FileInfo, err error) error { if err != nil { return err } else if info.IsDir() { @@ -108,9 +107,423 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { } return nil }) - if err != nil || totalCount == 0 { - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 18)) - return + + type tuneValue struct { + ID uint16 + Value uint16 + } + + tuneValues := []tuneValue{ + {ID: 20, Value: 1}, + {ID: 26, Value: 1}, + {ID: 27, Value: 1}, + {ID: 33, Value: 1}, + {ID: 40, Value: 1}, + {ID: 49, Value: 1}, + {ID: 53, Value: 1}, + {ID: 59, Value: 1}, + {ID: 67, Value: 1}, + {ID: 80, Value: 1}, + {ID: 94, Value: 1}, + {ID: 1010, Value: 300}, + {ID: 1011, Value: 300}, + {ID: 1012, Value: 300}, + {ID: 1013, Value: 300}, + {ID: 1014, Value: 200}, + {ID: 1015, Value: 200}, + {ID: 1021, Value: 400}, + {ID: 1023, Value: 8}, + {ID: 1024, Value: 150}, + {ID: 1025, Value: 1}, + {ID: 1026, Value: 999}, // get_grank_cap + {ID: 1027, Value: 100}, + {ID: 1028, Value: 100}, + {ID: 1030, Value: 8}, + {ID: 1031, Value: 100}, + {ID: 1032, Value: 0}, // isValid_partner + {ID: 1044, Value: 200}, // get_rate_tload_time_out + {ID: 1045, Value: 0}, // get_rate_tower_treasure_preset + {ID: 1046, Value: 99}, + {ID: 1048, Value: 0}, // get_rate_tower_log_disable + {ID: 1049, Value: 10}, // get_rate_tower_gem_max + {ID: 1050, Value: 1}, // get_rate_tower_gem_set + {ID: 1051, Value: 200}, + {ID: 1052, Value: 200}, + {ID: 1063, Value: 50000}, + {ID: 1064, Value: 50000}, + {ID: 1065, Value: 25000}, + {ID: 1066, Value: 25000}, + {ID: 1067, Value: 90}, // get_lobby_member_upper_for_making_room Lv1? + {ID: 1068, Value: 80}, // get_lobby_member_upper_for_making_room Lv2? + {ID: 1069, Value: 70}, // get_lobby_member_upper_for_making_room Lv3? + {ID: 1072, Value: 300}, // get_rate_premium_ravi_tama + {ID: 1073, Value: 300}, // get_rate_premium_ravi_ax_tama + {ID: 1074, Value: 300}, // get_rate_premium_ravi_g_tama + {ID: 1078, Value: 0}, + {ID: 1079, Value: 1}, + {ID: 1080, Value: 1}, + {ID: 1081, Value: 1}, + {ID: 1082, Value: 4}, + {ID: 1083, Value: 2}, + {ID: 1084, Value: 10}, + {ID: 1085, Value: 1}, + {ID: 1086, Value: 4}, + {ID: 1087, Value: 2}, + {ID: 1088, Value: 10}, + {ID: 1089, Value: 1}, + {ID: 1090, Value: 3}, + {ID: 1091, Value: 2}, + {ID: 1092, Value: 10}, + {ID: 1093, Value: 2}, + {ID: 1094, Value: 5}, + {ID: 1095, Value: 2}, + {ID: 1096, Value: 10}, + {ID: 1097, Value: 2}, + {ID: 1098, Value: 5}, + {ID: 1099, Value: 2}, + {ID: 1100, Value: 10}, + {ID: 1101, Value: 2}, + {ID: 1102, Value: 5}, + {ID: 1103, Value: 2}, + {ID: 1104, Value: 10}, + {ID: 1145, Value: 200}, + {ID: 1146, Value: 0}, // isTower_invisible + {ID: 1147, Value: 0}, // isVenom_playable + {ID: 1149, Value: 20}, + {ID: 1152, Value: 1130}, + {ID: 1154, Value: 0}, // isDisabled_object_season + {ID: 1158, Value: 1}, + {ID: 1160, Value: 300}, + {ID: 1162, Value: 1}, + {ID: 1163, Value: 3}, + {ID: 1164, Value: 5}, + {ID: 1165, Value: 1}, + {ID: 1166, Value: 5}, + {ID: 1167, Value: 1}, + {ID: 1168, Value: 3}, + {ID: 1169, Value: 3}, + {ID: 1170, Value: 5}, + {ID: 1171, Value: 1}, + {ID: 1172, Value: 1}, + {ID: 1173, Value: 1}, + {ID: 1174, Value: 2}, + {ID: 1175, Value: 4}, + {ID: 1176, Value: 10}, + {ID: 1177, Value: 4}, + {ID: 1178, Value: 10}, + {ID: 1179, Value: 2}, + {ID: 1180, Value: 5}, + {ID: 3000, Value: 100}, + {ID: 3001, Value: 100}, + {ID: 3002, Value: 100}, + {ID: 3003, Value: 100}, + {ID: 3004, Value: 100}, + {ID: 3005, Value: 100}, + {ID: 3006, Value: 100}, + {ID: 3007, Value: 100}, + {ID: 3008, Value: 100}, + {ID: 3009, Value: 100}, + {ID: 3010, Value: 100}, + {ID: 3011, Value: 100}, + {ID: 3012, Value: 100}, + {ID: 3013, Value: 100}, + {ID: 3014, Value: 100}, + {ID: 3015, Value: 100}, + {ID: 3016, Value: 100}, + {ID: 3017, Value: 100}, + {ID: 3018, Value: 100}, + {ID: 3019, Value: 100}, + {ID: 3020, Value: 100}, + {ID: 3021, Value: 100}, + {ID: 3022, Value: 100}, + {ID: 3023, Value: 100}, + {ID: 3024, Value: 100}, + {ID: 3025, Value: 100}, + {ID: 3286, Value: 200}, + {ID: 3287, Value: 200}, + {ID: 3288, Value: 200}, + {ID: 3289, Value: 200}, + {ID: 3290, Value: 200}, + {ID: 3291, Value: 200}, + {ID: 3292, Value: 200}, + {ID: 3293, Value: 200}, + {ID: 3294, Value: 200}, + {ID: 3295, Value: 200}, + {ID: 3296, Value: 200}, + {ID: 3297, Value: 200}, + {ID: 3298, Value: 200}, + {ID: 3299, Value: 200}, + {ID: 3300, Value: 200}, + {ID: 3301, Value: 200}, + {ID: 3302, Value: 200}, + {ID: 3303, Value: 200}, + {ID: 3304, Value: 200}, + {ID: 3305, Value: 200}, + {ID: 3306, Value: 200}, + {ID: 3307, Value: 200}, + {ID: 3308, Value: 200}, + {ID: 3309, Value: 200}, + {ID: 3310, Value: 200}, + {ID: 3311, Value: 200}, + {ID: 3312, Value: 300}, + {ID: 3313, Value: 300}, + {ID: 3314, Value: 300}, + {ID: 3315, Value: 300}, + {ID: 3316, Value: 300}, + {ID: 3317, Value: 300}, + {ID: 3318, Value: 300}, + {ID: 3319, Value: 300}, + {ID: 3320, Value: 300}, + {ID: 3321, Value: 300}, + {ID: 3322, Value: 300}, + {ID: 3323, Value: 300}, + {ID: 3324, Value: 300}, + {ID: 3325, Value: 300}, + {ID: 3326, Value: 300}, + {ID: 3327, Value: 300}, + {ID: 3328, Value: 300}, + {ID: 3329, Value: 300}, + {ID: 3330, Value: 300}, + {ID: 3331, Value: 300}, + {ID: 3332, Value: 300}, + {ID: 3333, Value: 300}, + {ID: 3334, Value: 300}, + {ID: 3335, Value: 300}, + {ID: 3336, Value: 300}, + {ID: 3337, Value: 300}, + {ID: 3338, Value: 100}, + {ID: 3339, Value: 100}, + {ID: 3340, Value: 100}, + {ID: 3341, Value: 100}, + {ID: 3342, Value: 100}, + {ID: 3343, Value: 100}, + {ID: 3344, Value: 100}, + {ID: 3345, Value: 100}, + {ID: 3346, Value: 100}, + {ID: 3347, Value: 100}, + {ID: 3348, Value: 100}, + {ID: 3349, Value: 100}, + {ID: 3350, Value: 100}, + {ID: 3351, Value: 100}, + {ID: 3352, Value: 100}, + {ID: 3353, Value: 100}, + {ID: 3354, Value: 100}, + {ID: 3355, Value: 100}, + {ID: 3356, Value: 100}, + {ID: 3357, Value: 100}, + {ID: 3358, Value: 100}, + {ID: 3359, Value: 100}, + {ID: 3360, Value: 100}, + {ID: 3361, Value: 100}, + {ID: 3362, Value: 100}, + {ID: 3363, Value: 100}, + {ID: 3364, Value: 100}, + {ID: 3365, Value: 100}, + {ID: 3366, Value: 100}, + {ID: 3367, Value: 100}, + {ID: 3368, Value: 100}, + {ID: 3369, Value: 100}, + {ID: 3370, Value: 100}, + {ID: 3371, Value: 100}, + {ID: 3372, Value: 100}, + {ID: 3373, Value: 100}, + {ID: 3374, Value: 100}, + {ID: 3375, Value: 100}, + {ID: 3376, Value: 100}, + {ID: 3377, Value: 100}, + {ID: 3378, Value: 100}, + {ID: 3379, Value: 100}, + {ID: 3380, Value: 100}, + {ID: 3381, Value: 100}, + {ID: 3382, Value: 100}, + {ID: 3383, Value: 100}, + {ID: 3384, Value: 100}, + {ID: 3385, Value: 100}, + {ID: 3386, Value: 100}, + {ID: 3387, Value: 100}, + {ID: 3388, Value: 100}, + {ID: 3389, Value: 100}, + {ID: 3390, Value: 100}, + {ID: 3391, Value: 100}, + {ID: 3392, Value: 100}, + {ID: 3393, Value: 100}, + {ID: 3394, Value: 100}, + {ID: 3395, Value: 100}, + {ID: 3396, Value: 100}, + {ID: 3397, Value: 100}, + {ID: 3398, Value: 100}, + {ID: 3399, Value: 100}, + {ID: 3400, Value: 100}, + {ID: 3401, Value: 100}, + {ID: 3402, Value: 100}, + {ID: 3416, Value: 100}, + {ID: 3417, Value: 100}, + {ID: 3418, Value: 100}, + {ID: 3419, Value: 100}, + {ID: 3420, Value: 100}, + {ID: 3421, Value: 100}, + {ID: 3422, Value: 100}, + {ID: 3423, Value: 100}, + {ID: 3424, Value: 100}, + {ID: 3425, Value: 100}, + {ID: 3426, Value: 100}, + {ID: 3427, Value: 100}, + {ID: 3428, Value: 100}, + {ID: 3442, Value: 100}, + {ID: 3443, Value: 100}, + {ID: 3444, Value: 100}, + {ID: 3445, Value: 100}, + {ID: 3446, Value: 100}, + {ID: 3447, Value: 100}, + {ID: 3448, Value: 100}, + {ID: 3449, Value: 100}, + {ID: 3450, Value: 100}, + {ID: 3451, Value: 100}, + {ID: 3452, Value: 100}, + {ID: 3453, Value: 100}, + {ID: 3454, Value: 100}, + {ID: 3468, Value: 100}, + {ID: 3469, Value: 100}, + {ID: 3470, Value: 100}, + {ID: 3471, Value: 100}, + {ID: 3472, Value: 100}, + {ID: 3473, Value: 100}, + {ID: 3474, Value: 100}, + {ID: 3475, Value: 100}, + {ID: 3476, Value: 100}, + {ID: 3477, Value: 100}, + {ID: 3478, Value: 100}, + {ID: 3479, Value: 100}, + {ID: 3480, Value: 100}, + {ID: 3494, Value: 0}, + {ID: 3495, Value: 0}, + {ID: 3496, Value: 0}, + {ID: 3497, Value: 0}, + {ID: 3498, Value: 0}, + {ID: 3499, Value: 0}, + {ID: 3500, Value: 0}, + {ID: 3501, Value: 0}, + {ID: 3502, Value: 0}, + {ID: 3503, Value: 0}, + {ID: 3504, Value: 0}, + {ID: 3505, Value: 0}, + {ID: 3506, Value: 0}, + {ID: 3520, Value: 0}, + {ID: 3521, Value: 0}, + {ID: 3522, Value: 0}, + {ID: 3523, Value: 0}, + {ID: 3524, Value: 0}, + {ID: 3525, Value: 0}, + {ID: 3526, Value: 0}, + {ID: 3527, Value: 0}, + {ID: 3528, Value: 0}, + {ID: 3529, Value: 0}, + {ID: 3530, Value: 0}, + {ID: 3531, Value: 0}, + {ID: 3532, Value: 0}, + {ID: 3546, Value: 0}, + {ID: 3547, Value: 0}, + {ID: 3548, Value: 0}, + {ID: 3549, Value: 0}, + {ID: 3550, Value: 0}, + {ID: 3551, Value: 0}, + {ID: 3552, Value: 0}, + {ID: 3553, Value: 0}, + {ID: 3554, Value: 0}, + {ID: 3555, Value: 0}, + {ID: 3556, Value: 0}, + {ID: 3557, Value: 0}, + {ID: 3558, Value: 0}, + {ID: 3572, Value: 0}, + {ID: 3573, Value: 0}, + {ID: 3574, Value: 0}, + {ID: 3575, Value: 0}, + {ID: 3576, Value: 0}, + {ID: 3577, Value: 0}, + {ID: 3578, Value: 0}, + {ID: 3579, Value: 0}, + {ID: 3580, Value: 0}, + {ID: 3581, Value: 0}, + {ID: 3582, Value: 0}, + {ID: 3583, Value: 0}, + {ID: 3584, Value: 0}, + } + + tuneValues = append(tuneValues, tuneValue{1020, uint16(s.server.erupeConfig.GameplayOptions.GCPMultiplier * 100)}) + + tuneValues = append(tuneValues, tuneValue{1029, s.server.erupeConfig.GameplayOptions.GUrgentRate}) + + if s.server.erupeConfig.GameplayOptions.DisableHunterNavi { + tuneValues = append(tuneValues, tuneValue{1037, 1}) + } + + if s.server.erupeConfig.GameplayOptions.EnableKaijiEvent { + tuneValues = append(tuneValues, tuneValue{1106, 1}) + } else { + tuneValues = append(tuneValues, tuneValue{1106, 0}) + } + + if s.server.erupeConfig.GameplayOptions.EnableHiganjimaEvent { + tuneValues = append(tuneValues, tuneValue{1144, 1}) + } else { + tuneValues = append(tuneValues, tuneValue{1144, 0}) + } + + if s.server.erupeConfig.GameplayOptions.EnableNierEvent { + tuneValues = append(tuneValues, tuneValue{1153, 1}) + } else { + tuneValues = append(tuneValues, tuneValue{1153, 0}) + } + + if s.server.erupeConfig.GameplayOptions.DisableRoad { + tuneValues = append(tuneValues, tuneValue{1155, 1}) + } else { + tuneValues = append(tuneValues, tuneValue{1155, 0}) + } + + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3026, uint16(s.server.erupeConfig.GameplayOptions.GRPMultiplier * 100)}) + } + + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3039, uint16(s.server.erupeConfig.GameplayOptions.GSRPMultiplier * 100)}) + } + + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3052, uint16(s.server.erupeConfig.GameplayOptions.GZennyMultiplier * 100)}) + } + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3078, uint16(s.server.erupeConfig.GameplayOptions.GZennyMultiplier * 100)}) + } + + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3104, uint16(s.server.erupeConfig.GameplayOptions.MaterialMultiplier * 100)}) + } + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3130, uint16(s.server.erupeConfig.GameplayOptions.MaterialMultiplier * 100)}) + } + + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3156, s.server.erupeConfig.GameplayOptions.ExtraCarves}) + } + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3182, s.server.erupeConfig.GameplayOptions.ExtraCarves}) + } + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3208, s.server.erupeConfig.GameplayOptions.ExtraCarves}) + } + for i := uint16(0); i < 13; i++ { + tuneValues = append(tuneValues, tuneValue{i + 3234, s.server.erupeConfig.GameplayOptions.ExtraCarves}) + } + + offset := uint16(time.Now().Unix()) + bf.WriteUint16(offset) + bf.WriteUint16(uint16(len(tuneValues))) + for i := range tuneValues { + bf.WriteUint16(tuneValues[i].ID ^ offset) + bf.WriteUint16(offset) + bf.WriteBytes(make([]byte, 4)) + bf.WriteUint16(tuneValues[i].Value ^ offset) } vsQuestItems := []uint16{1580, 1581, 1582, 1583, 1584, 1585, 1587, 1588, 1589, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604} @@ -123,10 +536,6 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { {false, 5000}, {false, 10000}, } - - data, _ := hex.DecodeString("06E601CF051406E6D4D4D40007CA02F006E6D4D4D4000685051506E6D4D4D40007CA051206E6D4D4D40007CA051306E6D4D4D40007CA02DC06E6D4D4D40006E202D806E6D4D4D40006E202A406E6D4D4D40006E5026806E6D4D4D40006E3027406E6D4D4D40006E3027006E6D4D4D40006E4026506E6D4D4D40006E602E006E6D4D4D40006EE02E706E6D4D4D40006E70B4006E6D4D4D40006E602E206E6D4D4D400068202E506E6D4D4D400068206C706E6D4D4D40006E706B606E6D4D4D40006E706D706E6D4D4D40006E706F206E6D4D4D40006E706DD06E6D4D4D40006E706D306E6D4D4D40006E706FC06E6D4D4D40006E706B806E6D4D4D40006E706CE06E6D4D4D40006E706FD06E6D4D4D40006E706A506E6D4D4D40006E7051906E6D4D4D40006EE02E606E6D4D4D40006700B4106E6D4D4D40006E60B4E06E6D4D4D40006E60B4F06E6D4D4D40006E60B4C06E6D4D4D40006E60B4D06E6D4D4D40006E60B4A06E6D4D4D40006E60B4B06E6D4D4D40006E60B4806E6D4D4D40006E60B4906E6D4D4D40006E60B5606E6D4D4D40006E60B5706E6D4D4D40006E60B5406E6D4D4D40006E60B2606E6D4D4D40006E60B2706E6D4D4D40006E602DE06E6D4D4D40006E702DF06E6D4D4D40006E70B2406E6D4D4D40006E60B2506E6D4D4D40006E60A3006E6D4D4D400062E0A3106E6D4D4D400062E0A3E06E6D4D4D400062E0B2206E6D4D4D40006E60B2306E6D4D4D40006E60B2006E6D4D4D40006E60B2106E6D4D4D40006E60B2E06E6D4D4D40006E60B2F06E6D4D4D40006E6051A06E6D4D4D4000682051B06E6D4D4D400077602CD06E6D4D4D40006BC0B2C06E6D4D4D40006E60A3F06E6D4D4D400062E0A3C06E6D4D4D400062E0A3D06E6D4D4D400062E0A3A06E6D4D4D400062E0A3B06E6D4D4D400062E0A3806E6D4D4D400062E0A3906E6D4D4D400062E0A0606E6D4D4D400062E0A0706E6D4D4D400062E0A0406E6D4D4D400062E0A0506E6D4D4D400062E0A0206E6D4D4D400062E0A0306E6D4D4D400062E0A0006E6D4D4D400062E0A0106E6D4D4D400062E0A0E06E6D4D4D400062E0A0F06E6D4D4D400062E0A0C06E6D4D4D400062E0A0D06E6D4D4D400062E0A0A06E6D4D4D400062E0A0B06E6D4D4D400062E0A0806E6D4D4D400062E0A0906E6D4D4D400062E0A1606E6D4D4D40007CA0A1706E6D4D4D40007CA0A1406E6D4D4D40007CA0A1506E6D4D4D40007CA0A1206E6D4D4D40007CA0A1306E6D4D4D40007CA0A1006E6D4D4D40007CA0A1106E6D4D4D40007CA0A1E06E6D4D4D40007CA0A1F06E6D4D4D40007CA0A1C06E6D4D4D40007CA0A1D06E6D4D4D40007CA0A1A06E6D4D4D40007CA0A1B06E6D4D4D40007CA0A1806E6D4D4D40007CA0A1906E6D4D4D40007CA0BE606E6D4D4D40007CA0BE706E6D4D4D40007CA0BE406E6D4D4D40007CA0BE506E6D4D4D40007CA0BE206E6D4D4D40007CA0B2D06E6D4D4D40006E60B2A06E6D4D4D40006E60BE306E6D4D4D40007CA02D606E6D4D4D40007CA029F06E6D4D4D400062E0B9406E6D4D4D40006820BE006E6D4D4D40007CA0BE106E6D4D4D40007CA0BEE06E6D4D4D40007CA0BEF06E6D4D4D40007CA02C106E6D4D4D400C5B602CE06E6D4D4D400C5B602CF06E6D4D4D400674E02CC06E6D4D4D400674E051006E6D4D4D400062E02FA06E6D4D4D400062E02CA06E6D4D4D40006B602CB06E6D4D4D40006A0051106E6D4D4D400062E02FD06E6D4D4D400062E0B9506E6D4D4D40006820B9206E6D4D4D40006820B9306E6D4D4D40006820B9006E6D4D4D40006820B9106E6D4D4D40006820B9E06E6D4D4D40006820B9F06E6D4D4D40006820BEC06E6D4D4D40006820BED06E6D4D4D40006820BEA06E6D4D4D40006820BEB06E6D4D4D40006820BE806E6D4D4D40006820BE906E6D4D4D40006820BF606E6D4D4D40006820BF706E6D4D4D40006820BF406E6D4D4D40006820BF506E6D4D4D40006820BF206E6D4D4D40006820BF306E6D4D4D40006820BF006E6D4D4D40006820BF106E6D4D4D400068202DB06E6D4D4D40006E70B9C06E6D4D4D40006820BFE06E6D4D4D40006820BFF06E6D4D4D400068202A706E6D4D4D40006E70B9D06E6D4D4D40006820BFC06E6D4D4D400068202D106E6D4D4D40006E702DD06E6D4D4D40006E402DA06E6D4D4D40006EC02D906E6D4D4D40006E402A606E6D4D4D40006EC02A506E6D4D4D40006E402A206E6D4D4D40006EC02A106E6D4D4D40006E402AE06E6D4D4D40006EC02AD06E6D4D4D40006E402AA06E6D4D4D40006EC02A906E6D4D4D40006E402B606E6D4D4D40006EC0BFD06E6D4D4D40006820BFA06E6D4D4D40006820BFB06E6D4D4D40006820BF806E6D4D4D40006820BF906E6D4D4D40006820BC606E6D4D4D40006820BC706E6D4D4D40006820BC406E6D4D4D40006820BC506E6D4D4D40006820BC206E6D4D4D40006820BC306E6D4D4D40006820BC006E6D4D4D40006820BC106E6D4D4D40006820BCE06E6D4D4D40006820BCF06E6D4D4D40006820BCC06E6D4D4D40006820BCD06E6D4D4D40006820BCA06E6D4D4D40006820BCB06E6D4D4D40006820BC806E6D4D4D40006820BC906E6D4D4D40006820BD606E6D4D4D40006820BD706E6D4D4D40006820BD406E6D4D4D40006820BD506E6D4D4D40006820BD206E6D4D4D40006820BD306E6D4D4D40006820BD006E6D4D4D40006820BD106E6D4D4D40006820BDE06E6D4D4D40006820BDF06E6D4D4D40006820BDC06E6D4D4D40006820BDD06E6D4D4D40006820BDA06E6D4D4D40006820BDB06E6D4D4D40006820B9A06E6D4D4D40006820BD806E6D4D4D40006820BD906E6D4D4D40006820BA606E6D4D4D40006820BA706E6D4D4D40006820BA406E6D4D4D40006820BA506E6D4D4D40006820BA206E6D4D4D40006820BA306E6D4D4D40006820BA006E6D4D4D40006820BA106E6D4D4D40006820BAE06E6D4D4D40006820BAF06E6D4D4D40006820BAC06E6D4D4D40006820BBE06E6D4D4D40006820BBF06E6D4D4D40006820BBC06E6D4D4D40006820BBD06E6D4D4D40006820BBA06E6D4D4D40006820BBB06E6D4D4D40006820BB806E6D4D4D40006820BB906E6D4D4D40006820B8606E6D4D4D40006820B8706E6D4D4D40006820B8406E6D4D4D40006820B8506E6D4D4D40006820B8206E6D4D4D400068202D706E6D4D4D40007CA02D406E6D4D4D40007CA026E06E6D4D4D40007CA0B9B06E6D4D4D40006820B9806E6D4D4D40006820B6A06E6D4D4D40006820B6B06E6D4D4D4000682029C06E6D4D4D40006E60B6806E6D4D4D4000682029D06E6D4D4D40006E60B6906E6D4D4D40006820A6E06E6D4D4D40006E60A6F06E6D4D4D40006E60A6C06E6D4D4D40006E60A6D06E6D4D4D40006E60A6A06E6D4D4D40006E60A6B06E6D4D4D40006E60A6806E6D4D4D40006E60A6906E6D4D4D40006E60A7606E6D4D4D40006E60A7706E6D4D4D40006E602E406E6D4D4D40005010A7406E6D4D4D40006E60A7506E6D4D4D40006E602D006E6D4D4D40006E60A7206E6D4D4D40006E6026606E6D4D4D400028C0A4406E6D4D4D40006E60A4506E6D4D4D40006E6026C06E6D4D4D40006E7026D06E6D4D4D40006E5026A06E6D4D4D40006E3026B06E6D4D4D40006E70A4206E6D4D4D40006E6026906E6D4D4D40006E7027606E6D4D4D40006E5027706E6D4D4D40006E50A4306E6D4D4D40006E6027506E6D4D4D40006E7027206E6D4D4D40006E7027306E6D4D4D40006E70A4006E6D4D4D40006E60A4106E6D4D4D40006E60A4E06E6D4D4D40006E60A4F06E6D4D4D40006E60A4C06E6D4D4D40006E60A4D06E6D4D4D40006E60A4A06E6D4D4D40006E60A4B06E6D4D4D40006E60A4806E6D4D4D40006E6029E06E6D4D4D40006E602A306E6D4D4D40006E402A006E6D4D4D40006E302AF06E6D4D4D40006E402AC06E6D4D4D40006E302AB06E6D4D4D40006E402A806E6D4D4D40006E3027106E6D4D4D40006E2027E06E6D4D4D40006EC027F06E6D4D4D40006E2027C06E6D4D4D40006EC027D06E6D4D4D40006E40B7606E6D4D4D40006820B7706E6D4D4D40006820B7406E6D4D4D40006820B7506E6D4D4D40006820B7206E6D4D4D40006820B7306E6D4D4D40006820B7006E6D4D4D40006820B7106E6D4D4D40006820B7E06E6D4D4D40006820B3C06E6D4D4D40006E60D3406E6D4D4D40006820D3506E6D4D4D40006820B3D06E6D4D4D40006E6026706E6D4D4D40006E60D5E06E6D4D4D40006820D5F06E6D4D4D40006820D5C06E6D4D4D40006820D5D06E6D4D4D40006820D5A06E6D4D4D40006820D5B06E6D4D4D40006820D5806E6D4D4D40006820D5906E6D4D4D40006820D2606E6D4D4D40006820D2706E6D4D4D40006820D2406E6D4D4D40006820D2506E6D4D4D40006820D2206E6D4D4D40006820D3206E6D4D4D40006820D3306E6D4D4D40006820D3006E6D4D4D40006820D3106E6D4D4D40006820D3E06E6D4D4D40006820D2306E6D4D4D40006820D2006E6D4D4D40006820D2106E6D4D4D40006820D2E06E6D4D4D40006820D2F06E6D4D4D40006820D2C06E6D4D4D40006820D2D06E6D4D4D40006820D2A06E6D4D4D40006820D2B06E6D4D4D40006820D2806E6D4D4D40006820D2906E6D4D4D40006820D3606E6D4D4D40006820D3706E6D4D4D400068202E306E6D4D4D40006F802E106E6D4D4D40006820D3F06E6D4D4D40006820D0A06E6D4D4D40006820D0B06E6D4D4D40006820D0806E6D4D4D40006820D0906E6D4D4D40006820D1606E6D4D4D40006820D1706E6D4D4D40006820D1406E6D4D4D40006820D1506E6D4D4D40006820D1206E6D4D4D40006820D3C06E6D4D4D400068202B406E6D4D4D40006E60D1306E6D4D4D40006820D1006E6D4D4D40006820D1106E6D4D4D40006820D1E06E6D4D4D40006820AE006E6D4D4D40006820AE106E6D4D4D40006820AEE06E6D4D4D40006820AEF06E6D4D4D40006820AEC06E6D4D4D40006820AED06E6D4D4D40006820AEA06E6D4D4D40006820AEB06E6D4D4D40006820AE806E6D4D4D40006820AE906E6D4D4D40006820AF606E6D4D4D4000682026406E6D4D4D40006E60AF706E6D4D4D40006820B3A06E6D4D4D40006E60AB206E6D4D4D40006E60B3B06E6D4D4D40006E60D3D06E6D4D4D40006820D3A06E6D4D4D40006820D3B06E6D4D4D40006820AB306E6D4D4D40006E60AB006E6D4D4D40006E60AB106E6D4D4D40006E60ABE06E6D4D4D40006E60ABF06E6D4D4D40006E60ABC06E6D4D4D40006E60ABD06E6D4D4D40006E60ABA06E6D4D4D40006E60ABB06E6D4D4D40006E60AB806E6D4D4D40006E60AB906E6D4D4D40006E60A8606E6D4D4D40006E60A8806E6D4D4D40006E60A8906E6D4D4D40006E60A9606E6D4D4D40006E60A9706E6D4D4D40006E60A9406E6D4D4D40006E60A9506E6D4D4D40006E60A9206E6D4D4D40006E60A9306E6D4D4D40006E60A9006E6D4D4D40006E60A9106E6D4D4D40006E60A9E06E6D4D4D40006E60A9F06E6D4D4D40006E60A9C06E6D4D4D40006E60D3806E6D4D4D40006820D3906E6D4D4D40006820D0606E6D4D4D40006820D0706E6D4D4D40006820D0406E6D4D4D40006820D0506E6D4D4D40006820D0206E6D4D4D40006820D0306E6D4D4D40006820D0006E6D4D4D40006820D0106E6D4D4D40006820D0E06E6D4D4D40006820D0F06E6D4D4D40006820D0C06E6D4D4D40006820D0D06E6D4D4D40006820B3806E6D4D4D40006E60B3906E6D4D4D40006E60B0606E6D4D4D40006E60B0706E6D4D4D40006E60B0406E6D4D4D40006E60B0506E6D4D4D40006E60B0206E6D4D4D40006E60B0306E6D4D4D40006E60B0006E6D4D4D40006E60B1206E6D4D4D40006E60B1306E6D4D4D40006E60B1006E6D4D4D40006E60B1106E6D4D4D40006E60B1E06E6D4D4D40006E60B1F06E6D4D4D40006E60B1C06E6D4D4D40006E60B1D06E6D4D4D40006E60B1A06E6D4D4D40006E60B1B06E6D4D4D40006E60B1806E6D4D4D40006E60B1906E6D4D4D40006E608E606E6D4D4D40006E6029B06E6D4D4D40006F20AF406E6D4D4D4000682026006E6D4D4D40006E70AC606E6D4D4D40006820AC706E6D4D4D40006820AC406E6D4D4D40006820AC506E6D4D4D40006820AC206E6D4D4D40006820AC306E6D4D4D40006820AC006E6D4D4D40006820AC106E6D4D4D40006820ACE06E6D4D4D40006820ACF06E6D4D4D40006820ACC06E6D4D4D40006820ACD06E6D4D4D40006820ACA06E6D4D4D4000682027A06E6D4D4D40006E30ADC06E6D4D4D40006820ADD06E6D4D4D40006820ADA06E6D4D4D40006820ADB06E6D4D4D40006820AD806E6D4D4D40006820AD906E6D4D4D40006820AA606E6D4D4D40006820AA706E6D4D4D40006820AA406E6D4D4D40006820AA506E6D4D4D40006820AA206E6D4D4D40006820AA306E6D4D4D40006820AA006E6D4D4D4000682") - bf.WriteBytes(data) - bf.WriteUint16(uint16(len(vsQuestItems))) bf.WriteUint32(uint32(len(vsQuestBets))) bf.WriteUint16(0) // Unk diff --git a/server/channelserver/handlers_seibattle.go b/server/channelserver/handlers_seibattle.go new file mode 100644 index 000000000..caf5c19c9 --- /dev/null +++ b/server/channelserver/handlers_seibattle.go @@ -0,0 +1,106 @@ +package channelserver + +import ( + "erupe-ce/common/byteframe" + "erupe-ce/network/mhfpacket" +) + +func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetBreakSeibatuLevelReward) + bf := byteframe.NewByteFrame() + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} + +type WeeklySeibatuRankingReward struct { + Unk0 int32 + Unk1 int32 + Unk2 uint32 + Unk3 int32 + Unk4 int32 + Unk5 int32 +} + +func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetWeeklySeibatuRankingReward) + var data []*byteframe.ByteFrame + weeklySeibatuRankingRewards := []WeeklySeibatuRankingReward{ + {0, 0, 0, 0, 0, 0}, + } + for _, reward := range weeklySeibatuRankingRewards { + bf := byteframe.NewByteFrame() + bf.WriteInt32(reward.Unk0) + bf.WriteInt32(reward.Unk1) + bf.WriteUint32(reward.Unk2) + bf.WriteInt32(reward.Unk3) + bf.WriteInt32(reward.Unk4) + bf.WriteInt32(reward.Unk5) + data = append(data, bf) + } + doAckEarthSucceed(s, pkt.AckHandle, data) +} + +func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetFixedSeibatuRankingTable) + bf := byteframe.NewByteFrame() + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteBytes(make([]byte, 32)) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} + +func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadBeatLevel) + + // This response is fixed and will never change on JP, + // but I've left it dynamic for possible other client differences. + resp := byteframe.NewByteFrame() + for i := 0; i < int(pkt.ValidIDCount); i++ { + resp.WriteUint32(pkt.IDs[i]) + resp.WriteUint32(1) + resp.WriteUint32(1) + resp.WriteUint32(1) + } + + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadLastWeekBeatRanking) + bf := byteframe.NewByteFrame() + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} + +func handleMsgMhfUpdateBeatLevel(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfUpdateBeatLevel) + + doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadBeatLevelAllRanking) + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + + for i := 0; i < 100; i++ { + bf.WriteUint32(0) + bf.WriteUint32(0) + bf.WriteBytes(make([]byte, 32)) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} + +func handleMsgMhfReadBeatLevelMyRanking(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadBeatLevelMyRanking) + bf := byteframe.NewByteFrame() + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} diff --git a/server/channelserver/handlers_tournament.go b/server/channelserver/handlers_tournament.go index 84c2c8e8f..87fc95330 100644 --- a/server/channelserver/handlers_tournament.go +++ b/server/channelserver/handlers_tournament.go @@ -7,54 +7,124 @@ import ( "time" ) +type TournamentInfo0 struct { + ID uint32 + MaxPlayers uint32 + CurrentPlayers uint32 + Unk1 uint16 + TextColor uint16 + Unk2 uint32 + Time1 time.Time + Time2 time.Time + Time3 time.Time + Time4 time.Time + Time5 time.Time + Time6 time.Time + Unk3 uint8 + Unk4 uint8 + MinHR uint32 + MaxHR uint32 + Unk5 string + Unk6 string +} + +type TournamentInfo21 struct { + Unk0 uint32 + Unk1 uint32 + Unk2 uint32 + Unk3 uint8 +} + +type TournamentInfo22 struct { + Unk0 uint32 + Unk1 uint32 + Unk2 uint32 + Unk3 uint8 + Unk4 string +} + func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfInfoTournament) bf := byteframe.NewByteFrame() + tournamentInfo0 := []TournamentInfo0{} + tournamentInfo21 := []TournamentInfo21{} + tournamentInfo22 := []TournamentInfo22{} + switch pkt.Unk0 { case 0: - bf.WriteUint32(uint32(TimeAdjusted().Unix())) - bf.WriteUint32(0) // Tied to schedule ID? - case 1: - - bf.WriteBytes(make([]byte, 21)) - ps.Uint8(bf, "", false) - break - - bf.WriteUint32(0xACEDCAFE) - - bf.WriteUint32(5) // Active schedule? - - bf.WriteUint32(1) // Schedule ID? - - bf.WriteUint32(32) // Max players - bf.WriteUint32(0) // Registered players - - bf.WriteUint16(0) - bf.WriteUint16(2) // Color code for schedule item bf.WriteUint32(0) - - bf.WriteUint32(uint32(time.Now().Add(time.Hour * -10).Unix())) - bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix())) - bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix())) - bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix())) - bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix())) - bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix())) - - bf.WriteBool(true) // Unk - bf.WriteBool(false) // Cafe-only - - bf.WriteUint32(0) // Min HR - bf.WriteUint32(0) // Max HR - - ps.Uint8(bf, "Test", false) - - // ... + bf.WriteUint32(uint32(len(tournamentInfo0))) + for _, tinfo := range tournamentInfo0 { + bf.WriteUint32(tinfo.ID) + bf.WriteUint32(tinfo.MaxPlayers) + bf.WriteUint32(tinfo.CurrentPlayers) + bf.WriteUint16(tinfo.Unk1) + bf.WriteUint16(tinfo.TextColor) + bf.WriteUint32(tinfo.Unk2) + bf.WriteUint32(uint32(tinfo.Time1.Unix())) + bf.WriteUint32(uint32(tinfo.Time2.Unix())) + bf.WriteUint32(uint32(tinfo.Time3.Unix())) + bf.WriteUint32(uint32(tinfo.Time4.Unix())) + bf.WriteUint32(uint32(tinfo.Time5.Unix())) + bf.WriteUint32(uint32(tinfo.Time6.Unix())) + bf.WriteUint8(tinfo.Unk3) + bf.WriteUint8(tinfo.Unk4) + bf.WriteUint32(tinfo.MinHR) + bf.WriteUint32(tinfo.MaxHR) + ps.Uint8(bf, tinfo.Unk5, true) + ps.Uint16(bf, tinfo.Unk6, true) + } + case 1: + bf.WriteUint32(uint32(TimeAdjusted().Unix())) + bf.WriteUint32(0) // Registered ID + bf.WriteUint32(0) + bf.WriteUint32(0) + bf.WriteUint8(0) + bf.WriteUint32(0) + ps.Uint8(bf, "", true) + case 2: + bf.WriteUint32(0) + bf.WriteUint32(uint32(len(tournamentInfo21))) + for _, info := range tournamentInfo21 { + bf.WriteUint32(info.Unk0) + bf.WriteUint32(info.Unk1) + bf.WriteUint32(info.Unk2) + bf.WriteUint8(info.Unk3) + } + bf.WriteUint32(uint32(len(tournamentInfo22))) + for _, info := range tournamentInfo22 { + bf.WriteUint32(info.Unk0) + bf.WriteUint32(info.Unk1) + bf.WriteUint32(info.Unk2) + bf.WriteUint8(info.Unk3) + ps.Uint8(bf, info.Unk4, true) + } } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } -func handleMsgMhfEntryTournament(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfEntryTournament(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEntryTournament) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} -func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) {} +type TournamentReward struct { + Unk0 uint16 + Unk1 uint16 + Unk2 uint16 +} + +func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfAcquireTournament) + rewards := []TournamentReward{} + bf := byteframe.NewByteFrame() + bf.WriteUint8(uint8(len(rewards))) + for _, reward := range rewards { + bf.WriteUint16(reward.Unk0) + bf.WriteUint16(reward.Unk1) + bf.WriteUint16(reward.Unk2) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} diff --git a/server/channelserver/handlers_tower.go b/server/channelserver/handlers_tower.go index 0a2675812..a9bc1421c 100644 --- a/server/channelserver/handlers_tower.go +++ b/server/channelserver/handlers_tower.go @@ -1,102 +1,477 @@ package channelserver import ( - "encoding/hex" + "fmt" + "go.uber.org/zap" + "time" + + "erupe-ce/common/byteframe" + "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" ) +type TowerInfoTRP struct { + TR int32 + TRP int32 +} + +type TowerInfoSkill struct { + TSP int32 + Unk1 []int16 // 40 +} + +type TowerInfoHistory struct { + Unk0 []int16 // 5 + Unk1 []int16 // 5 +} + +type TowerInfoLevel struct { + Floors int32 + Unk1 int32 + Unk2 int32 + Unk3 int32 +} + func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetTowerInfo) - var data []byte - var err error - /* - type: - 1 == TOWER_RANK_POINT, - 2 == GET_OWN_TOWER_SKILL - 3 == GET_OWN_TOWER_LEVEL_V3 - 4 == TOWER_TOUHA_HISTORY - 5 = ? - - [] = type - req - resp - - 01 1d 01 fc 00 09 [00 00 00 01] 00 00 00 02 00 00 00 00 - 00 12 01 fc 00 09 01 00 00 18 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 - - 01 1d 01 fc 00 0a [00 00 00 02] 00 00 00 00 00 00 00 00 - 00 12 01 fc 00 0a 01 00 00 94 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - - 01 1d 01 ff 00 0f [00 00 00 04] 00 00 00 00 00 00 00 00 - 00 12 01 ff 00 0f 01 00 00 24 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - - 01 1d 01 fc 00 0b [00 00 00 05] 00 00 00 00 00 00 00 00 - 00 12 01 fc 00 0b 01 00 00 10 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 00 - */ - switch pkt.InfoType { - case mhfpacket.TowerInfoTypeTowerRankPoint: - data, err = hex.DecodeString("0A218EAD0000000000000000000000010000000000000000") - case mhfpacket.TowerInfoTypeGetOwnTowerSkill: - //data, err = hex.DecodeString("0A218EAD000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - data, err = hex.DecodeString("0A218EAD0000000000000000000000010000001C0000000500050000000000020000000000000000000000000000000000030003000000000003000500050000000300030003000300030003000200030001000300020002000300010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - case mhfpacket.TowerInfoTypeGetOwnTowerLevelV3: - panic("No known response values for GetOwnTowerLevelV3") - case mhfpacket.TowerInfoTypeTowerTouhaHistory: - data, err = hex.DecodeString("0A218EAD0000000000000000000000010000000000000000000000000000000000000000") - case mhfpacket.TowerInfoTypeUnk5: - data, err = hex.DecodeString("0A218EAD000000000000000000000000") + var data []*byteframe.ByteFrame + type TowerInfo struct { + TRP []TowerInfoTRP + Skill []TowerInfoSkill + History []TowerInfoHistory + Level []TowerInfoLevel } + towerInfo := TowerInfo{ + TRP: []TowerInfoTRP{{0, 0}}, + Skill: []TowerInfoSkill{{0, make([]int16, 40)}}, + History: []TowerInfoHistory{{make([]int16, 5), make([]int16, 5)}}, + Level: []TowerInfoLevel{{0, 0, 0, 0}, {0, 0, 0, 0}}, + } + + tempSkills := "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" + + err := s.server.db.QueryRow(`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), skills FROM tower WHERE char_id=$1 + `, s.charID).Scan(&towerInfo.TRP[0].TR, &towerInfo.TRP[0].TRP, &towerInfo.Skill[0].TSP, &towerInfo.Level[0].Floors, &towerInfo.Level[1].Floors, &tempSkills) if err != nil { - stubGetNoResults(s, pkt.AckHandle) + s.server.db.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, s.charID) } - doAckBufSucceed(s, pkt.AckHandle, data) + + for i, skill := range stringsupport.CSVElems(tempSkills) { + towerInfo.Skill[0].Unk1[i] = int16(skill) + } + + switch pkt.InfoType { + case 1: + for _, trp := range towerInfo.TRP { + bf := byteframe.NewByteFrame() + bf.WriteInt32(trp.TR) + bf.WriteInt32(trp.TRP) + data = append(data, bf) + } + case 2: + for _, skills := range towerInfo.Skill { + bf := byteframe.NewByteFrame() + bf.WriteInt32(skills.TSP) + for i := range skills.Unk1 { + bf.WriteInt16(skills.Unk1[i]) + } + data = append(data, bf) + } + case 4: + for _, history := range towerInfo.History { + bf := byteframe.NewByteFrame() + for i := range history.Unk0 { + bf.WriteInt16(history.Unk0[i]) + } + for i := range history.Unk1 { + bf.WriteInt16(history.Unk1[i]) + } + data = append(data, bf) + } + case 5: + for _, level := range towerInfo.Level { + bf := byteframe.NewByteFrame() + bf.WriteInt32(level.Floors) + bf.WriteInt32(level.Unk1) + bf.WriteInt32(level.Unk2) + bf.WriteInt32(level.Unk3) + data = append(data, bf) + } + } + doAckEarthSucceed(s, pkt.AckHandle, data) } func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfPostTowerInfo) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + + if s.server.erupeConfig.DevModeOptions.QuestDebugTools { + s.logger.Debug( + p.Opcode().String(), + zap.Uint32("InfoType", pkt.InfoType), + zap.Uint32("Unk1", pkt.Unk1), + zap.Int32("Skill", pkt.Skill), + zap.Int32("TR", pkt.TR), + zap.Int32("TRP", pkt.TRP), + zap.Int32("Cost", pkt.Cost), + zap.Int32("Unk6", pkt.Unk6), + zap.Int32("Unk7", pkt.Unk7), + zap.Int32("Block1", pkt.Block1), + zap.Int64("Unk9", pkt.Unk9), + ) + } + + switch pkt.InfoType { + case 2: + skills := "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" + s.server.db.QueryRow(`SELECT skills FROM tower WHERE char_id=$1`, s.charID).Scan(&skills) + s.server.db.Exec(`UPDATE tower SET skills=$1, tsp=tsp-$2 WHERE char_id=$3`, stringsupport.CSVSetIndex(skills, int(pkt.Skill), stringsupport.CSVGetIndex(skills, int(pkt.Skill))+1), pkt.Cost, s.charID) + case 7: + s.server.db.Exec(`UPDATE tower SET tr=$1, trp=trp+$2, block1=block1+$3 WHERE char_id=$4`, pkt.TR, pkt.TRP, pkt.Block1, s.charID) + } + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} + +// Default missions +var tenrouiraiData = []TenrouiraiData{ + {1, 1, 80, 0, 2, 2, 1, 1, 2, 2}, + {1, 4, 16, 0, 2, 2, 1, 1, 2, 2}, + {1, 6, 50, 0, 2, 2, 1, 0, 2, 2}, + {1, 4, 12, 50, 2, 2, 1, 1, 2, 2}, + {1, 3, 50, 0, 2, 2, 1, 1, 2, 2}, + {2, 5, 40000, 0, 2, 2, 1, 0, 2, 2}, + {1, 5, 50000, 50, 2, 2, 1, 1, 2, 2}, + {2, 1, 60, 0, 2, 2, 1, 1, 2, 2}, + {2, 3, 50, 0, 2, 1, 1, 0, 1, 2}, + {2, 3, 40, 50, 2, 1, 1, 1, 1, 2}, + {2, 4, 12, 0, 2, 1, 1, 1, 1, 2}, + {2, 6, 40, 0, 2, 1, 1, 0, 1, 2}, + {1, 1, 60, 50, 2, 1, 2, 1, 1, 2}, + {1, 5, 50000, 0, 3, 1, 2, 1, 1, 2}, + {1, 6, 50, 0, 3, 1, 2, 0, 1, 2}, + {1, 4, 16, 50, 3, 1, 2, 1, 1, 2}, + {1, 5, 50000, 0, 3, 1, 2, 1, 1, 2}, + {2, 3, 40, 0, 3, 1, 2, 0, 1, 2}, + {1, 3, 50, 50, 3, 1, 2, 1, 1, 2}, + {2, 5, 40000, 0, 3, 1, 2, 1, 1, 1}, + {2, 6, 40, 0, 3, 1, 2, 0, 1, 1}, + {2, 1, 60, 50, 3, 1, 2, 1, 1, 1}, + {2, 6, 50, 0, 3, 1, 2, 1, 1, 1}, + {2, 4, 12, 0, 3, 1, 2, 0, 1, 1}, + {1, 1, 80, 50, 3, 1, 2, 1, 1, 1}, + {1, 5, 40000, 0, 3, 1, 2, 1, 1, 1}, + {1, 3, 50, 0, 3, 1, 2, 0, 1, 1}, + {1, 4, 16, 50, 3, 1, 0, 1, 1, 1}, + {1, 6, 50, 0, 3, 1, 0, 1, 1, 1}, + {2, 3, 40, 0, 3, 1, 0, 1, 1, 1}, + {1, 1, 80, 50, 3, 1, 0, 0, 1, 1}, + {2, 5, 40000, 0, 3, 1, 0, 0, 1, 1}, + {2, 6, 40, 0, 3, 1, 0, 0, 1, 1}, +} + +type TenrouiraiProgress struct { + Page uint8 + Mission1 uint16 + Mission2 uint16 + Mission3 uint16 +} + +type TenrouiraiReward struct { + Index uint8 + Item []uint16 // 5 + Quantity []uint8 // 5 +} + +type TenrouiraiKeyScore struct { + Unk0 uint8 + Unk1 int32 +} + +type TenrouiraiData struct { + Block uint8 + Mission uint8 + // 1 = Floors climbed + // 2 = Collect antiques + // 3 = Open chests + // 4 = Cats saved + // 5 = TRP acquisition + // 6 = Monster slays + Goal uint16 + Cost uint16 + Skill1 uint8 // 80 + Skill2 uint8 // 40 + Skill3 uint8 // 40 + Skill4 uint8 // 20 + Skill5 uint8 // 40 + Skill6 uint8 // 50 +} + +type TenrouiraiCharScore struct { + Score int32 + Name string +} + +type TenrouiraiTicket struct { + Unk0 uint8 + RP uint32 + Unk2 uint32 +} + +type Tenrouirai struct { + Progress []TenrouiraiProgress + Reward []TenrouiraiReward + KeyScore []TenrouiraiKeyScore + Data []TenrouiraiData + CharScore []TenrouiraiCharScore + Ticket []TenrouiraiTicket } func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) { - // if the game gets bad responses for this it breaks the ability to save pkt := p.(*mhfpacket.MsgMhfGetTenrouirai) - var data []byte - var err error - if pkt.Unk0 == 1 { - data, err = hex.DecodeString("0A218EAD000000000000000000000001010000000000060010") - } else if pkt.Unk2 == 4 { - data, err = hex.DecodeString("0A218EAD0000000000000000000000210101005000000202010102020104001000000202010102020106003200000202010002020104000C003202020101020201030032000002020101020202059C4000000202010002020105C35000320202010102020201003C00000202010102020203003200000201010001020203002800320201010101020204000C00000201010101020206002800000201010001020101003C00320201020101020105C35000000301020101020106003200000301020001020104001000320301020101020105C350000003010201010202030028000003010200010201030032003203010201010202059C4000000301020101010206002800000301020001010201003C00320301020101010206003200000301020101010204000C000003010200010101010050003203010201010101059C40000003010201010101030032000003010200010101040010003203010001010101060032000003010001010102030028000003010001010101010050003203010000010102059C4000000301000001010206002800000301000001010010") - } else { - data = []byte{0x00, 0x00, 0x00, 0x00} - s.logger.Info("GET_TENROUIRAI request for unknown type") + var data []*byteframe.ByteFrame + + tenrouirai := Tenrouirai{ + Progress: []TenrouiraiProgress{{1, 0, 0, 0}}, + Data: tenrouiraiData, + Ticket: []TenrouiraiTicket{{0, 0, 0}}, } - if err != nil { - panic(err) + + switch pkt.Unk1 { + case 1: + for _, tdata := range tenrouirai.Data { + bf := byteframe.NewByteFrame() + bf.WriteUint8(tdata.Block) + bf.WriteUint8(tdata.Mission) + bf.WriteUint16(tdata.Goal) + bf.WriteUint16(tdata.Cost) + bf.WriteUint8(tdata.Skill1) + bf.WriteUint8(tdata.Skill2) + bf.WriteUint8(tdata.Skill3) + bf.WriteUint8(tdata.Skill4) + bf.WriteUint8(tdata.Skill5) + bf.WriteUint8(tdata.Skill6) + data = append(data, bf) + } + case 2: + for _, reward := range tenrouirai.Reward { + bf := byteframe.NewByteFrame() + bf.WriteUint8(reward.Index) + bf.WriteUint16(reward.Item[0]) + bf.WriteUint16(reward.Item[1]) + bf.WriteUint16(reward.Item[2]) + bf.WriteUint16(reward.Item[3]) + bf.WriteUint16(reward.Item[4]) + bf.WriteUint8(reward.Quantity[0]) + bf.WriteUint8(reward.Quantity[1]) + bf.WriteUint8(reward.Quantity[2]) + bf.WriteUint8(reward.Quantity[3]) + bf.WriteUint8(reward.Quantity[4]) + data = append(data, bf) + } + case 4: + s.server.db.QueryRow(`SELECT tower_mission_page FROM guilds WHERE id=$1`, pkt.GuildID).Scan(&tenrouirai.Progress[0].Page) + s.server.db.QueryRow(`SELECT SUM(tower_mission_1) AS _, SUM(tower_mission_2) AS _, SUM(tower_mission_3) AS _ FROM guild_characters WHERE guild_id=$1 + `, pkt.GuildID).Scan(&tenrouirai.Progress[0].Mission1, &tenrouirai.Progress[0].Mission2, &tenrouirai.Progress[0].Mission3) + + if tenrouirai.Progress[0].Mission1 > tenrouiraiData[(tenrouirai.Progress[0].Page*3)-3].Goal { + tenrouirai.Progress[0].Mission1 = tenrouiraiData[(tenrouirai.Progress[0].Page*3)-3].Goal + } + if tenrouirai.Progress[0].Mission2 > tenrouiraiData[(tenrouirai.Progress[0].Page*3)-2].Goal { + tenrouirai.Progress[0].Mission2 = tenrouiraiData[(tenrouirai.Progress[0].Page*3)-2].Goal + } + if tenrouirai.Progress[0].Mission3 > tenrouiraiData[(tenrouirai.Progress[0].Page*3)-1].Goal { + tenrouirai.Progress[0].Mission3 = tenrouiraiData[(tenrouirai.Progress[0].Page*3)-1].Goal + } + + for _, progress := range tenrouirai.Progress { + bf := byteframe.NewByteFrame() + bf.WriteUint8(progress.Page) + bf.WriteUint16(progress.Mission1) + bf.WriteUint16(progress.Mission2) + bf.WriteUint16(progress.Mission3) + data = append(data, bf) + } + case 5: + if pkt.Unk3 > 3 { + pkt.Unk3 %= 3 + if pkt.Unk3 == 0 { + pkt.Unk3 = 3 + } + } + rows, _ := s.server.db.Query(fmt.Sprintf(`SELECT name, tower_mission_%d FROM guild_characters gc INNER JOIN characters c ON gc.character_id = c.id WHERE guild_id=$1 AND tower_mission_%d IS NOT NULL ORDER BY tower_mission_%d DESC`, pkt.Unk3, pkt.Unk3, pkt.Unk3), pkt.GuildID) + for rows.Next() { + temp := TenrouiraiCharScore{} + rows.Scan(&temp.Name, &temp.Score) + tenrouirai.CharScore = append(tenrouirai.CharScore, temp) + } + for _, charScore := range tenrouirai.CharScore { + bf := byteframe.NewByteFrame() + bf.WriteInt32(charScore.Score) + bf.WriteBytes(stringsupport.PaddedString(charScore.Name, 14, true)) + data = append(data, bf) + } + case 6: + s.server.db.QueryRow(`SELECT tower_rp FROM guilds WHERE id=$1`, pkt.GuildID).Scan(&tenrouirai.Ticket[0].RP) + for _, ticket := range tenrouirai.Ticket { + bf := byteframe.NewByteFrame() + bf.WriteUint8(ticket.Unk0) + bf.WriteUint32(ticket.RP) + bf.WriteUint32(ticket.Unk2) + data = append(data, bf) + } } - doAckBufSucceed(s, pkt.AckHandle, data) + + doAckEarthSucceed(s, pkt.AckHandle, data) } func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfPostTenrouirai) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) -} -func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {} + if s.server.erupeConfig.DevModeOptions.QuestDebugTools { + s.logger.Debug( + p.Opcode().String(), + zap.Uint8("Unk0", pkt.Unk0), + zap.Uint8("Op", pkt.Op), + zap.Uint32("GuildID", pkt.GuildID), + zap.Uint8("Unk1", pkt.Unk1), + zap.Uint16("Floors", pkt.Floors), + zap.Uint16("Antiques", pkt.Antiques), + zap.Uint16("Chests", pkt.Chests), + zap.Uint16("Cats", pkt.Cats), + zap.Uint16("TRP", pkt.TRP), + zap.Uint16("Slays", pkt.Slays), + ) + } -func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfGetWeeklySeibatuRankingReward) - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + if pkt.Op == 2 { + var page, requirement, donated int + s.server.db.QueryRow(`SELECT tower_mission_page, tower_rp FROM guilds WHERE id=$1`, pkt.GuildID).Scan(&page, &donated) + + for i := 0; i < (page*3)+1; i++ { + requirement += int(tenrouiraiData[i].Cost) + } + + bf := byteframe.NewByteFrame() + + sd, err := GetCharacterSaveData(s, s.charID) + if err == nil && sd != nil { + sd.RP -= pkt.DonatedRP + sd.Save(s) + if donated+int(pkt.DonatedRP) >= requirement { + s.server.db.Exec(`UPDATE guilds SET tower_mission_page=tower_mission_page+1 WHERE id=$1`, pkt.GuildID) + s.server.db.Exec(`UPDATE guild_characters SET tower_mission_1=NULL, tower_mission_2=NULL, tower_mission_3=NULL WHERE guild_id=$1`, pkt.GuildID) + pkt.DonatedRP = uint16(requirement - donated) + } + bf.WriteUint32(uint32(pkt.DonatedRP)) + s.server.db.Exec(`UPDATE guilds SET tower_rp=tower_rp+$1 WHERE id=$2`, pkt.DonatedRP, pkt.GuildID) + } else { + bf.WriteUint32(0) + } + + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) + } else { + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + } } func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfPresentBox) - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + var data []*byteframe.ByteFrame + /* + bf.WriteUint32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + bf.WriteInt32(0) + */ + doAckEarthSucceed(s, pkt.AckHandle, data) +} + +type GemInfo struct { + Gem uint16 + Quantity uint16 +} + +type GemHistory struct { + Gem uint16 + Message uint16 + Timestamp time.Time + Sender string } func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGemInfo) + var data []*byteframe.ByteFrame + gemInfo := []GemInfo{} + gemHistory := []GemHistory{} + + tempGems := "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" + s.server.db.QueryRow(`SELECT gems FROM tower WHERE char_id=$1`, s.charID).Scan(&tempGems) + for i, v := range stringsupport.CSVElems(tempGems) { + gemInfo = append(gemInfo, GemInfo{uint16(((i / 5) * 256) + ((i % 5) + 1)), uint16(v)}) + } + + switch pkt.Unk0 { + case 1: + for _, info := range gemInfo { + bf := byteframe.NewByteFrame() + bf.WriteUint16(info.Gem) + bf.WriteUint16(info.Quantity) + data = append(data, bf) + } + case 2: + for _, history := range gemHistory { + bf := byteframe.NewByteFrame() + bf.WriteUint16(history.Gem) + bf.WriteUint16(history.Message) + bf.WriteUint32(uint32(history.Timestamp.Unix())) + bf.WriteBytes(stringsupport.PaddedString(history.Sender, 14, true)) + data = append(data, bf) + } + } + doAckEarthSucceed(s, pkt.AckHandle, data) +} + +func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfPostGemInfo) + + if s.server.erupeConfig.DevModeOptions.QuestDebugTools { + s.logger.Debug( + p.Opcode().String(), + zap.Uint32("Op", pkt.Op), + zap.Uint32("Unk1", pkt.Unk1), + zap.Int32("Gem", pkt.Gem), + zap.Int32("Quantity", pkt.Quantity), + zap.Int32("CID", pkt.CID), + zap.Int32("Message", pkt.Message), + zap.Int32("Unk6", pkt.Unk6), + ) + } + + gems := "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" + s.server.db.QueryRow(`SELECT gems FROM tower WHERE char_id=$1`, s.charID).Scan(&gems) + switch pkt.Op { + case 1: // Add gem + i := int(((pkt.Gem / 256) * 5) + (((pkt.Gem - ((pkt.Gem / 256) * 256)) - 1) % 5)) + s.server.db.Exec(`UPDATE tower SET gems=$1 WHERE char_id=$2`, stringsupport.CSVSetIndex(gems, i, stringsupport.CSVGetIndex(gems, i)+int(pkt.Quantity)), s.charID) + case 2: // Transfer gem + // no way im doing this for now + } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } -func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfGetNotice(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetNotice) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} + +func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfPostNotice) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 309ed1af8..dccece844 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -22,7 +22,7 @@ type Config struct { Logger *zap.Logger DB *sqlx.DB DiscordBot *discordbot.DiscordBot - ErupeConfig *config.Config + ErupeConfig *_config.Config Name string Enable bool } @@ -43,7 +43,7 @@ type Server struct { Port uint16 logger *zap.Logger db *sqlx.DB - erupeConfig *config.Config + erupeConfig *_config.Config acceptConns chan net.Conn deleteConns chan net.Conn sessions map[net.Conn]*Session diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go index b69995724..7b8fb15eb 100644 --- a/server/channelserver/sys_stage.go +++ b/server/channelserver/sys_stage.go @@ -30,7 +30,7 @@ type Stage struct { // Objects objects map[uint32]*Object - objectIndex uint8 + objectIndex uint16 // Map of session -> charID. // These are clients that are CURRENTLY in the stage @@ -56,7 +56,6 @@ func NewStage(ID string) *Stage { clients: make(map[*Session]uint32), reservedClientSlots: make(map[uint32]bool), objects: make(map[uint32]*Object), - objectIndex: 0, rawBinaryData: make(map[stageBinaryKey][]byte), maxPlayers: 4, } @@ -97,16 +96,10 @@ func (s *Stage) isQuest() bool { } func (s *Stage) NextObjectID() uint32 { - s.objectIndex = s.objectIndex + 1 - // Objects beyond 127 do not duplicate correctly - // Indexes 0 and 127 does not update position correctly - if s.objectIndex == 127 { - s.objectIndex = 1 - } + s.objectIndex++ bf := byteframe.NewByteFrame() - bf.WriteUint8(0) - bf.WriteUint8(s.objectIndex) - bf.WriteUint16(0) - obj := uint32(bf.Data()[3]) | uint32(bf.Data()[2])<<8 | uint32(bf.Data()[1])<<16 | uint32(bf.Data()[0])<<24 - return obj + bf.WriteUint16(127) + bf.WriteUint16(s.objectIndex) + bf.Seek(0, 0) + return bf.ReadUint32() } diff --git a/server/discordbot/discord_bot.go b/server/discordbot/discord_bot.go index fc5c41ce8..c082faf70 100644 --- a/server/discordbot/discord_bot.go +++ b/server/discordbot/discord_bot.go @@ -9,14 +9,14 @@ import ( type DiscordBot struct { Session *discordgo.Session - config *config.Config + config *_config.Config logger *zap.Logger MainGuild *discordgo.Guild RealtimeChannel *discordgo.Channel } type Options struct { - Config *config.Config + Config *_config.Config Logger *zap.Logger } diff --git a/server/entranceserver/entrance_server.go b/server/entranceserver/entrance_server.go index c0a4e852b..8b06be0e0 100644 --- a/server/entranceserver/entrance_server.go +++ b/server/entranceserver/entrance_server.go @@ -18,7 +18,7 @@ import ( type Server struct { sync.Mutex logger *zap.Logger - erupeConfig *config.Config + erupeConfig *_config.Config db *sqlx.DB listener net.Listener isShuttingDown bool @@ -28,7 +28,7 @@ type Server struct { type Config struct { Logger *zap.Logger DB *sqlx.DB - ErupeConfig *config.Config + ErupeConfig *_config.Config } // NewServer creates a new Server type. @@ -68,7 +68,7 @@ func (s *Server) Shutdown() { s.listener.Close() } -//acceptClients handles accepting new clients in a loop. +// acceptClients handles accepting new clients in a loop. func (s *Server) acceptClients() { for { conn, err := s.listener.Accept() diff --git a/server/entranceserver/make_resp.go b/server/entranceserver/make_resp.go index 2d13709db..619296fdb 100644 --- a/server/entranceserver/make_resp.go +++ b/server/entranceserver/make_resp.go @@ -3,13 +3,12 @@ package entranceserver import ( "encoding/binary" "encoding/hex" + "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "fmt" "net" - "erupe-ce/common/stringsupport" - "erupe-ce/common/byteframe" - "erupe-ce/config" "erupe-ce/server/channelserver" ) @@ -19,11 +18,22 @@ var season uint8 // Server Channels var currentplayers uint16 -func encodeServerInfo(config *config.Config, s *Server, local bool) []byte { +func encodeServerInfo(config *_config.Config, s *Server, local bool) []byte { serverInfos := config.Entrance.Entries bf := byteframe.NewByteFrame() for serverIdx, si := range serverInfos { + // Prevent MezFes Worlds displaying on Z1 + if config.RealClientMode <= _config.Z1 { + if si.Type == 6 { + continue + } + } + if config.RealClientMode <= _config.G6 { + if si.Type == 5 { + continue + } + } sid := (4096 + serverIdx*256) + 16 err := s.db.QueryRow("SELECT season FROM servers WHERE server_id=$1", sid).Scan(&season) if err != nil { @@ -42,12 +52,29 @@ func encodeServerInfo(config *config.Config, s *Server, local bool) []byte { bf.WriteUint16(uint16(len(si.Channels))) bf.WriteUint8(si.Type) bf.WriteUint8(season) - bf.WriteUint8(si.Recommended) - bf.WriteUint8(0) // Prevents malformed server name - combined := append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...) - combined = append(combined, stringsupport.UTF8ToSJIS(si.Description)...) - bf.WriteBytes(stringsupport.PaddedString(string(combined), 65, false)) - bf.WriteUint32(si.AllowedClientFlags) + if s.erupeConfig.RealClientMode >= _config.G1 { + bf.WriteUint8(si.Recommended) + } + + if s.erupeConfig.RealClientMode <= _config.F5 { + combined := append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...) + combined = append(combined, stringsupport.UTF8ToSJIS(si.Description)...) + bf.WriteBytes(stringsupport.PaddedString(string(combined), 65, false)) + } else if s.erupeConfig.RealClientMode <= _config.GG { + combined := append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...) + combined = append(combined, stringsupport.UTF8ToSJIS(si.Description)...) + bf.WriteUint8(uint8(len(combined))) + bf.WriteBytes(combined) + } else { + bf.WriteUint8(0) // Prevents malformed server name + combined := append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...) + combined = append(combined, stringsupport.UTF8ToSJIS(si.Description)...) + bf.WriteBytes(stringsupport.PaddedString(string(combined), 65, false)) + } + + if s.erupeConfig.RealClientMode >= _config.GG { + bf.WriteUint32(si.AllowedClientFlags) + } for channelIdx, ci := range si.Channels { sid = (4096 + serverIdx*256) + (16 + channelIdx) @@ -91,16 +118,39 @@ func makeHeader(data []byte, respType string, entryCount uint16, key byte) []byt return bf.Data() } -func makeSv2Resp(config *config.Config, s *Server, local bool) []byte { +func makeSv2Resp(config *_config.Config, s *Server, local bool) []byte { serverInfos := config.Entrance.Entries + // Decrease by the number of MezFes Worlds + var mf int + if config.RealClientMode <= _config.Z1 { + for _, si := range serverInfos { + if si.Type == 6 { + mf++ + } + } + } + // and Return Worlds + var ret int + if config.RealClientMode <= _config.G6 { + for _, si := range serverInfos { + if si.Type == 5 { + ret++ + } + } + } rawServerData := encodeServerInfo(config, s, local) if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.LogOutboundMessages { fmt.Printf("[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(rawServerData), hex.Dump(rawServerData)) } + respType := "SV2" + if config.RealClientMode <= _config.G32 { + respType = "SVR" + } + bf := byteframe.NewByteFrame() - bf.WriteBytes(makeHeader(rawServerData, "SV2", uint16(len(serverInfos)), 0x00)) + bf.WriteBytes(makeHeader(rawServerData, respType, uint16(len(serverInfos)-(mf+ret)), 0x00)) return bf.Data() } diff --git a/server/signserver/dbutils.go b/server/signserver/dbutils.go index 0410f351d..da1e37843 100644 --- a/server/signserver/dbutils.go +++ b/server/signserver/dbutils.go @@ -12,15 +12,9 @@ import ( "golang.org/x/crypto/bcrypt" ) -func (s *Server) newUserChara(username string) error { - var id int - err := s.db.QueryRow("SELECT id FROM users WHERE username = $1", username).Scan(&id) - if err != nil { - return err - } - +func (s *Server) newUserChara(uid int) error { var numNewChars int - err = s.db.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", id).Scan(&numNewChars) + err := s.db.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", uid).Scan(&numNewChars) if err != nil { return err } @@ -35,7 +29,7 @@ func (s *Server) newUserChara(username string) error { user_id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login) VALUES($1, False, True, '', '', 0, 0, 0, $2)`, - id, + uid, uint32(time.Now().Unix()), ) if err != nil { @@ -60,19 +54,6 @@ func (s *Server) registerDBAccount(username string, password string) (uint32, er return 0, err } - // Create a base new character. - _, err = s.db.Exec(` - INSERT INTO characters ( - user_id, is_female, is_new_character, name, unk_desc_string, - hrp, gr, weapon_type, last_login) - VALUES($1, False, True, '', '', 0, 0, 0, $2)`, - uid, - uint32(time.Now().Unix()), - ) - if err != nil { - return 0, err - } - return uid, nil } @@ -90,7 +71,7 @@ type character struct { func (s *Server) getCharactersForUser(uid uint32) ([]character, error) { characters := make([]character, 0) - err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false ORDER BY id ASC", uid) + err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false ORDER BY id", uid) if err != nil { return nil, err } @@ -158,9 +139,6 @@ func (s *Server) getFriendsForCharacters(chars []character) []members { } friends = append(friends, charFriends...) } - if len(friends) > 255 { // Uint8 - friends = friends[:255] - } return friends } @@ -180,15 +158,12 @@ func (s *Server) getGuildmatesForCharacters(chars []character) []members { if err != nil { continue } - for i, _ := range charGuildmates { + for i := range charGuildmates { charGuildmates[i].CID = char.ID } guildmates = append(guildmates, charGuildmates...) } } - if len(guildmates) > 255 { // Uint8 - guildmates = guildmates[:255] - } return guildmates } diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index 03f9b8aee..d93730c92 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -4,6 +4,7 @@ import ( "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "erupe-ce/server/channelserver" "fmt" "go.uber.org/zap" @@ -13,6 +14,12 @@ import ( func (s *Session) makeSignResponse(uid uint32) []byte { // Get the characters from the DB. chars, err := s.server.getCharactersForUser(uid) + if len(chars) == 0 { + err = s.server.newUserChara(uid) + if err == nil { + chars, err = s.server.getCharactersForUser(uid) + } + } if err != nil { s.logger.Warn("Error getting characters from DB", zap.Error(err)) } @@ -30,7 +37,7 @@ func (s *Session) makeSignResponse(uid uint32) []byte { return bf.Data() } - bf.WriteUint8(1) // resp_code + bf.WriteUint8(uint8(SIGN_SUCCESS)) // resp_code if (s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "") || s.client == PS3 { bf.WriteUint8(2) } else { @@ -78,15 +85,23 @@ func (s *Session) makeSignResponse(uid uint32) []byte { bf.WriteBool(true) // Use uint16 GR, no reason not to bf.WriteBytes(stringsupport.PaddedString(char.Name, 16, true)) // Character name bf.WriteBytes(stringsupport.PaddedString(char.UnkDescString, 32, false)) // unk str - bf.WriteUint16(char.GR) - bf.WriteUint16(0) // Unk + if s.server.erupeConfig.RealClientMode >= _config.G7 { + bf.WriteUint16(char.GR) + bf.WriteUint8(0) // Unk + bf.WriteUint8(0) // Unk + } } friends := s.server.getFriendsForCharacters(chars) if len(friends) == 0 { bf.WriteUint8(0) } else { - bf.WriteUint8(uint8(len(friends))) + if len(friends) > 255 { + bf.WriteUint8(255) + bf.WriteUint16(uint16(len(friends))) + } else { + bf.WriteUint8(uint8(len(friends))) + } for _, friend := range friends { bf.WriteUint32(friend.CID) bf.WriteUint32(friend.ID) @@ -98,7 +113,12 @@ func (s *Session) makeSignResponse(uid uint32) []byte { if len(guildmates) == 0 { bf.WriteUint8(0) } else { - bf.WriteUint8(uint8(len(guildmates))) + if len(guildmates) > 255 { + bf.WriteUint8(255) + bf.WriteUint16(uint16(len(guildmates))) + } else { + bf.WriteUint8(uint8(len(guildmates))) + } for _, guildmate := range guildmates { bf.WriteUint32(guildmate.CID) bf.WriteUint32(guildmate.ID) @@ -107,12 +127,12 @@ func (s *Session) makeSignResponse(uid uint32) []byte { } if s.server.erupeConfig.HideLoginNotice { - bf.WriteUint8(0) + bf.WriteBool(false) } else { - bf.WriteUint8(uint8(len(s.server.erupeConfig.LoginNotices))) - for _, notice := range s.server.erupeConfig.LoginNotices { - ps.Uint32(bf, notice, true) - } + bf.WriteBool(true) + bf.WriteUint8(0) + bf.WriteUint8(0) + ps.Uint16(bf, strings.Join(s.server.erupeConfig.LoginNotices[:], ""), true) } bf.WriteUint32(s.server.getLastCID(uid)) @@ -132,35 +152,37 @@ func (s *Session) makeSignResponse(uid uint32) []byte { bf.WriteUint16(0x4E20) ps.Uint16(bf, "", false) // unk ipv4 bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix())) - bf.WriteUint32(0x00000000) - bf.WriteUint32(0x0A5197DF) // unk id + bf.WriteUint32(0) mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent alt := s.server.erupeConfig.DevModeOptions.MezFesAlt if mezfes { + // We can just use the start timestamp as the event ID + bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix())) // Start time bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix())) // End time bf.WriteUint32(uint32(channelserver.TimeWeekNext().Unix())) - bf.WriteUint8(2) // Unk - bf.WriteUint32(20) // Single tickets - bf.WriteUint32(10) // Group tickets - bf.WriteUint8(8) // Stalls open - bf.WriteUint8(0xA) // Unk - bf.WriteUint8(0x3) // Pachinko - bf.WriteUint8(0x6) // Nyanrendo - bf.WriteUint8(0x9) // Point stall + bf.WriteUint8(2) // Unk + bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MezfesSoloTickets) + bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MezfesGroupTickets) + bf.WriteUint8(8) // Stalls open + bf.WriteUint8(10) // Stall Map + bf.WriteUint8(3) // Pachinko + bf.WriteUint8(6) // Nyanrendo + bf.WriteUint8(9) // Point stall if alt { - bf.WriteUint8(0x2) // Tokotoko + bf.WriteUint8(2) // Tokotoko Partnya } else { - bf.WriteUint8(0x4) // Volpakkun + bf.WriteUint8(4) // Volpakkun Together } - bf.WriteUint8(0x8) // Battle cats - bf.WriteUint8(0x5) // Gook - bf.WriteUint8(0x7) // Honey + bf.WriteUint8(8) // Dokkan Battle Cats + bf.WriteUint8(5) // Goocoo Scoop + bf.WriteUint8(7) // Honey Panic } else { bf.WriteUint32(0) bf.WriteUint32(0) + bf.WriteUint32(0) } return bf.Data() } diff --git a/server/signserver/session.go b/server/signserver/session.go index 532998054..475203cc6 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -62,7 +62,7 @@ func (s *Session) handlePacket(pkt []byte) error { case "VITASGN:100": s.client = VITA s.handlePSSGN(bf) - case "WIIUSGN:100": + case "WIIUSGN:100", "WIIUSGN:000": s.client = WIIU s.handleWIIUSGN(bf) case "VITACOGLNK:100": @@ -124,6 +124,13 @@ func (s *Session) handleWIIUSGN(bf *byteframe.ByteFrame) { } func (s *Session) handlePSSGN(bf *byteframe.ByteFrame) { + // Prevent reading malformed request + if len(bf.DataFromCurrent()) < 128 { + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(SIGN_EABORT)) + s.cryptConn.SendPacket(resp.Data()) + return + } _ = bf.ReadNullTerminatedBytes() // VITA = 0000000256, PS3 = 0000000255 _ = bf.ReadBytes(2) // VITA = 1, PS3 = ! _ = bf.ReadBytes(82) diff --git a/server/signserver/sign_server.go b/server/signserver/sign_server.go index fd4bd9bed..f93a6459a 100644 --- a/server/signserver/sign_server.go +++ b/server/signserver/sign_server.go @@ -16,14 +16,14 @@ import ( type Config struct { Logger *zap.Logger DB *sqlx.DB - ErupeConfig *config.Config + ErupeConfig *_config.Config } // Server is a MHF sign server. type Server struct { sync.Mutex logger *zap.Logger - erupeConfig *config.Config + erupeConfig *_config.Config sessions map[int]*Session db *sqlx.DB listener net.Listener diff --git a/server/signv2server/signv2_server.go b/server/signv2server/signv2_server.go index c00a4a641..c6db00b09 100644 --- a/server/signv2server/signv2_server.go +++ b/server/signv2server/signv2_server.go @@ -18,14 +18,14 @@ import ( type Config struct { Logger *zap.Logger DB *sqlx.DB - ErupeConfig *config.Config + ErupeConfig *_config.Config } // Server is the MHF custom launcher sign server. type Server struct { sync.Mutex logger *zap.Logger - erupeConfig *config.Config + erupeConfig *_config.Config db *sqlx.DB httpServer *http.Server isShuttingDown bool