mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-04-05 15:32:29 +02:00
Merge remote-tracking branch 'origin/main' into feature/psn-link
# Conflicts: # server/signserver/dbutils.go # server/signserver/dsgn_resp.go # server/signserver/session.go
This commit is contained in:
134
README.md
134
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
|
## 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.
|
If you want to modify or compile Erupe yourself, please read on.
|
||||||
|
|
||||||
### Requirements
|
## Requirements
|
||||||
|
|
||||||
- [Go](https://go.dev/dl/)
|
- [Go](https://go.dev/dl/)
|
||||||
- [PostgreSQL](https://www.postgresql.org/download/)
|
- [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).
|
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.
|
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.
|
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.
|
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
|
## Resources
|
||||||
|
|
||||||
- [Quest and Scenario Binary Files](https://files.catbox.moe/xf0l7w.7z)
|
- [Quest and Scenario Binary Files](https://files.catbox.moe/xf0l7w.7z)
|
||||||
- [PewPewDojo Discord](https://discord.gg/CFnzbhQ)
|
- [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
|
||||||
@@ -66,7 +66,7 @@ func CourseExists(ID uint16, c []Course) bool {
|
|||||||
|
|
||||||
// GetCourseStruct returns a slice of Course(s) from a rights integer
|
// GetCourseStruct returns a slice of Course(s) from a rights integer
|
||||||
func GetCourseStruct(rights uint32) ([]Course, uint32) {
|
func GetCourseStruct(rights uint32) ([]Course, uint32) {
|
||||||
resp := []Course{{ID: 1}, {ID: 24}}
|
resp := []Course{{ID: 1}, {ID: 23}, {ID: 24}}
|
||||||
s := Courses()
|
s := Courses()
|
||||||
slices.SortStableFunc(s, func(i, j Course) bool {
|
slices.SortStableFunc(s, func(i, j Course) bool {
|
||||||
return i.ID > j.ID
|
return i.ID > j.ID
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package stringsupport
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -96,3 +97,23 @@ func CSVElems(csv string) []int {
|
|||||||
}
|
}
|
||||||
return r
|
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, ",")
|
||||||
|
}
|
||||||
|
|||||||
23
config.json
23
config.json
@@ -11,6 +11,7 @@
|
|||||||
"PatchServerFile": "",
|
"PatchServerFile": "",
|
||||||
"ScreenshotAPIURL": "",
|
"ScreenshotAPIURL": "",
|
||||||
"DeleteOnSaveCorruption": false,
|
"DeleteOnSaveCorruption": false,
|
||||||
|
"ClientMode": "ZZ",
|
||||||
"DevMode": true,
|
"DevMode": true,
|
||||||
"DevModeOptions": {
|
"DevModeOptions": {
|
||||||
"AutoCreateAccount": true,
|
"AutoCreateAccount": true,
|
||||||
@@ -26,21 +27,39 @@
|
|||||||
"MezFesAlt": false,
|
"MezFesAlt": false,
|
||||||
"DisableTokenCheck": false,
|
"DisableTokenCheck": false,
|
||||||
"QuestDebugTools": false,
|
"QuestDebugTools": false,
|
||||||
|
"EarthStatusOverride": 0,
|
||||||
|
"EarthIDOverride": 0,
|
||||||
|
"EarthMonsterOverride": 0,
|
||||||
"SaveDumps": {
|
"SaveDumps": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"OutputDir": "savedata"
|
"OutputDir": "save-backups"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"GameplayOptions": {
|
"GameplayOptions": {
|
||||||
"FeaturedWeapons": 1,
|
"FeaturedWeapons": 1,
|
||||||
"MaximumNP": 100000,
|
"MaximumNP": 100000,
|
||||||
"MaximumRP": 50000,
|
"MaximumRP": 50000,
|
||||||
|
"MaximumFP": 120000,
|
||||||
"DisableLoginBoost": false,
|
"DisableLoginBoost": false,
|
||||||
"DisableBoostTime": false,
|
"DisableBoostTime": false,
|
||||||
"BoostTimeDuration": 120,
|
"BoostTimeDuration": 120,
|
||||||
"GuildMealDuration": 60,
|
"GuildMealDuration": 60,
|
||||||
"BonusQuestAllowance": 3,
|
"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": {
|
"Discord": {
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
|
|||||||
@@ -1,15 +1,70 @@
|
|||||||
package config
|
package _config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"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.
|
// Config holds the global server-wide config.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Host string `mapstructure:"Host"`
|
Host string `mapstructure:"Host"`
|
||||||
@@ -22,6 +77,8 @@ type Config struct {
|
|||||||
PatchServerFile string // File patch server override
|
PatchServerFile string // File patch server override
|
||||||
ScreenshotAPIURL string // Destination for screenshots uploaded to BBS
|
ScreenshotAPIURL string // Destination for screenshots uploaded to BBS
|
||||||
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
|
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
|
||||||
|
ClientMode string
|
||||||
|
RealClientMode Mode
|
||||||
DevMode bool
|
DevMode bool
|
||||||
|
|
||||||
DevModeOptions DevModeOptions
|
DevModeOptions DevModeOptions
|
||||||
@@ -51,6 +108,9 @@ type DevModeOptions struct {
|
|||||||
MezFesAlt bool // Swaps out Volpakkun for Tokotoko
|
MezFesAlt bool // Swaps out Volpakkun for Tokotoko
|
||||||
DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
|
DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
|
||||||
QuestDebugTools bool // Enable various quest debug logs
|
QuestDebugTools bool // Enable various quest debug logs
|
||||||
|
EarthStatusOverride int32
|
||||||
|
EarthIDOverride int32
|
||||||
|
EarthMonsterOverride int32
|
||||||
SaveDumps SaveDumpOptions
|
SaveDumps SaveDumpOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,12 +124,27 @@ type GameplayOptions struct {
|
|||||||
FeaturedWeapons int // Number of Active Feature weapons to generate daily
|
FeaturedWeapons int // Number of Active Feature weapons to generate daily
|
||||||
MaximumNP int // Maximum number of NP held by a player
|
MaximumNP int // Maximum number of NP held by a player
|
||||||
MaximumRP uint16 // Maximum number of RP 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
|
DisableLoginBoost bool // Disables the Login Boost system
|
||||||
DisableBoostTime bool // Disables the daily NetCafe Boost Time
|
DisableBoostTime bool // Disables the daily NetCafe Boost Time
|
||||||
BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for
|
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
|
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
|
BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily
|
||||||
DailyQuestAllowance uint32 // Number of Daily 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.
|
// Discord holds the discord integration config.
|
||||||
@@ -154,7 +229,6 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
|
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOutboundIP4 gets the preferred outbound ip4 of this machine
|
// getOutboundIP4 gets the preferred outbound ip4 of this machine
|
||||||
@@ -196,6 +270,20 @@ func LoadConfig() (*Config, error) {
|
|||||||
c.Host = getOutboundIP4().To4().String()
|
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
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
main.go
64
main.go
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_config "erupe-ce/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -9,7 +10,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"erupe-ce/config"
|
|
||||||
"erupe-ce/server/channelserver"
|
"erupe-ce/server/channelserver"
|
||||||
"erupe-ce/server/discordbot"
|
"erupe-ce/server/discordbot"
|
||||||
"erupe-ce/server/entranceserver"
|
"erupe-ce/server/entranceserver"
|
||||||
@@ -45,7 +45,8 @@ func main() {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
var zapLogger *zap.Logger
|
var zapLogger *zap.Logger
|
||||||
if config.ErupeConfig.DevMode {
|
config := _config.ErupeConfig
|
||||||
|
if config.DevMode {
|
||||||
zapLogger, _ = zap.NewDevelopment()
|
zapLogger, _ = zap.NewDevelopment()
|
||||||
} else {
|
} else {
|
||||||
zapLogger, _ = zap.NewProduction()
|
zapLogger, _ = zap.NewProduction()
|
||||||
@@ -55,20 +56,21 @@ func main() {
|
|||||||
logger := zapLogger.Named("main")
|
logger := zapLogger.Named("main")
|
||||||
|
|
||||||
logger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit()))
|
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")
|
preventClose("Database password is blank")
|
||||||
}
|
}
|
||||||
|
|
||||||
if net.ParseIP(config.ErupeConfig.Host) == nil {
|
if net.ParseIP(config.Host) == nil {
|
||||||
ips, _ := net.LookupIP(config.ErupeConfig.Host)
|
ips, _ := net.LookupIP(config.Host)
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
if ip != nil {
|
if ip != nil {
|
||||||
config.ErupeConfig.Host = ip.String()
|
config.Host = ip.String()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if net.ParseIP(config.ErupeConfig.Host) == nil {
|
if net.ParseIP(config.Host) == nil {
|
||||||
preventClose("Invalid host address")
|
preventClose("Invalid host address")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,10 +78,10 @@ func main() {
|
|||||||
// Discord bot
|
// Discord bot
|
||||||
var discordBot *discordbot.DiscordBot = nil
|
var discordBot *discordbot.DiscordBot = nil
|
||||||
|
|
||||||
if config.ErupeConfig.Discord.Enabled {
|
if config.Discord.Enabled {
|
||||||
bot, err := discordbot.NewDiscordBot(discordbot.Options{
|
bot, err := discordbot.NewDiscordBot(discordbot.Options{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
Config: config.ErupeConfig,
|
Config: _config.ErupeConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -102,11 +104,11 @@ func main() {
|
|||||||
// Create the postgres DB pool.
|
// Create the postgres DB pool.
|
||||||
connectString := fmt.Sprintf(
|
connectString := fmt.Sprintf(
|
||||||
"host='%s' port='%d' user='%s' password='%s' dbname='%s' sslmode=disable",
|
"host='%s' port='%d' user='%s' password='%s' dbname='%s' sslmode=disable",
|
||||||
config.ErupeConfig.Database.Host,
|
config.Database.Host,
|
||||||
config.ErupeConfig.Database.Port,
|
config.Database.Port,
|
||||||
config.ErupeConfig.Database.User,
|
config.Database.User,
|
||||||
config.ErupeConfig.Database.Password,
|
config.Database.Password,
|
||||||
config.ErupeConfig.Database.Database,
|
config.Database.Database,
|
||||||
)
|
)
|
||||||
|
|
||||||
db, err := sqlx.Open("postgres", connectString)
|
db, err := sqlx.Open("postgres", connectString)
|
||||||
@@ -126,7 +128,7 @@ func main() {
|
|||||||
_ = db.MustExec("DELETE FROM servers")
|
_ = db.MustExec("DELETE FROM servers")
|
||||||
|
|
||||||
// Clean the DB if the option is on.
|
// 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...")
|
logger.Info("Database: Started clearing...")
|
||||||
cleanDB(db)
|
cleanDB(db)
|
||||||
logger.Info("Database: Finished clearing")
|
logger.Info("Database: Finished clearing")
|
||||||
@@ -139,11 +141,11 @@ func main() {
|
|||||||
// Entrance server.
|
// Entrance server.
|
||||||
|
|
||||||
var entranceServer *entranceserver.Server
|
var entranceServer *entranceserver.Server
|
||||||
if config.ErupeConfig.Entrance.Enabled {
|
if config.Entrance.Enabled {
|
||||||
entranceServer = entranceserver.NewServer(
|
entranceServer = entranceserver.NewServer(
|
||||||
&entranceserver.Config{
|
&entranceserver.Config{
|
||||||
Logger: logger.Named("entrance"),
|
Logger: logger.Named("entrance"),
|
||||||
ErupeConfig: config.ErupeConfig,
|
ErupeConfig: _config.ErupeConfig,
|
||||||
DB: db,
|
DB: db,
|
||||||
})
|
})
|
||||||
err = entranceServer.Start()
|
err = entranceServer.Start()
|
||||||
@@ -158,11 +160,11 @@ func main() {
|
|||||||
// Sign server.
|
// Sign server.
|
||||||
|
|
||||||
var signServer *signserver.Server
|
var signServer *signserver.Server
|
||||||
if config.ErupeConfig.Sign.Enabled {
|
if config.Sign.Enabled {
|
||||||
signServer = signserver.NewServer(
|
signServer = signserver.NewServer(
|
||||||
&signserver.Config{
|
&signserver.Config{
|
||||||
Logger: logger.Named("sign"),
|
Logger: logger.Named("sign"),
|
||||||
ErupeConfig: config.ErupeConfig,
|
ErupeConfig: _config.ErupeConfig,
|
||||||
DB: db,
|
DB: db,
|
||||||
})
|
})
|
||||||
err = signServer.Start()
|
err = signServer.Start()
|
||||||
@@ -176,11 +178,11 @@ func main() {
|
|||||||
|
|
||||||
// New Sign server
|
// New Sign server
|
||||||
var newSignServer *signv2server.Server
|
var newSignServer *signv2server.Server
|
||||||
if config.ErupeConfig.SignV2.Enabled {
|
if config.SignV2.Enabled {
|
||||||
newSignServer = signv2server.NewServer(
|
newSignServer = signv2server.NewServer(
|
||||||
&signv2server.Config{
|
&signv2server.Config{
|
||||||
Logger: logger.Named("sign"),
|
Logger: logger.Named("sign"),
|
||||||
ErupeConfig: config.ErupeConfig,
|
ErupeConfig: _config.ErupeConfig,
|
||||||
DB: db,
|
DB: db,
|
||||||
})
|
})
|
||||||
err = newSignServer.Start()
|
err = newSignServer.Start()
|
||||||
@@ -194,23 +196,23 @@ func main() {
|
|||||||
|
|
||||||
var channels []*channelserver.Server
|
var channels []*channelserver.Server
|
||||||
|
|
||||||
if config.ErupeConfig.Channel.Enabled {
|
if config.Channel.Enabled {
|
||||||
channelQuery := ""
|
channelQuery := ""
|
||||||
si := 0
|
si := 0
|
||||||
ci := 0
|
ci := 0
|
||||||
count := 1
|
count := 1
|
||||||
for j, ee := range config.ErupeConfig.Entrance.Entries {
|
for j, ee := range config.Entrance.Entries {
|
||||||
for i, ce := range ee.Channels {
|
for i, ce := range ee.Channels {
|
||||||
sid := (4096 + si*256) + (16 + ci)
|
sid := (4096 + si*256) + (16 + ci)
|
||||||
c := *channelserver.NewServer(&channelserver.Config{
|
c := *channelserver.NewServer(&channelserver.Config{
|
||||||
ID: uint16(sid),
|
ID: uint16(sid),
|
||||||
Logger: logger.Named("channel-" + fmt.Sprint(count)),
|
Logger: logger.Named("channel-" + fmt.Sprint(count)),
|
||||||
ErupeConfig: config.ErupeConfig,
|
ErupeConfig: _config.ErupeConfig,
|
||||||
DB: db,
|
DB: db,
|
||||||
DiscordBot: discordBot,
|
DiscordBot: discordBot,
|
||||||
})
|
})
|
||||||
if ee.IP == "" {
|
if ee.IP == "" {
|
||||||
c.IP = config.ErupeConfig.Host
|
c.IP = config.Host
|
||||||
} else {
|
} else {
|
||||||
c.IP = ee.IP
|
c.IP = ee.IP
|
||||||
}
|
}
|
||||||
@@ -246,7 +248,7 @@ func main() {
|
|||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
if !config.ErupeConfig.DisableSoftCrash {
|
if !config.DisableSoftCrash {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
message := fmt.Sprintf("Shutting down in %d...", 10-i)
|
message := fmt.Sprintf("Shutting down in %d...", 10-i)
|
||||||
for _, c := range channels {
|
for _, c := range channels {
|
||||||
@@ -257,21 +259,21 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ErupeConfig.Channel.Enabled {
|
if config.Channel.Enabled {
|
||||||
for _, c := range channels {
|
for _, c := range channels {
|
||||||
c.Shutdown()
|
c.Shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ErupeConfig.Sign.Enabled {
|
if config.Sign.Enabled {
|
||||||
signServer.Shutdown()
|
signServer.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ErupeConfig.SignV2.Enabled {
|
if config.SignV2.Enabled {
|
||||||
newSignServer.Shutdown()
|
newSignServer.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ErupeConfig.Entrance.Enabled {
|
if config.Entrance.Enabled {
|
||||||
entranceServer.Shutdown()
|
entranceServer.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +287,7 @@ func wait() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func preventClose(text string) {
|
func preventClose(text string) {
|
||||||
if config.ErupeConfig.DisableSoftCrash {
|
if _config.ErupeConfig.DisableSoftCrash {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
fmt.Println("\nFailed to start Erupe:\n" + text)
|
fmt.Println("\nFailed to start Erupe:\n" + text)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package network
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@@ -48,7 +49,14 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now read the encrypted packet body after getting its size from the header.
|
// 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)
|
_, err = io.ReadFull(cc.conn, encryptedPacketBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -56,7 +64,7 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) {
|
|||||||
|
|
||||||
// Update the key rotation before decrypting.
|
// Update the key rotation before decrypting.
|
||||||
if cph.KeyRotDelta != 0 {
|
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)
|
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)
|
keyRotDelta := byte(3)
|
||||||
|
|
||||||
if keyRotDelta != 0 {
|
if keyRotDelta != 0 {
|
||||||
cc.sendKeyRot = (uint32(keyRotDelta) * (cc.sendKeyRot + 1))
|
cc.sendKeyRot = uint32(keyRotDelta) * (cc.sendKeyRot + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the data
|
// Encrypt the data
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
"erupe-ce/network/clientctx"
|
"erupe-ce/network/clientctx"
|
||||||
"erupe-ce/common/byteframe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfAcquireCafeItem represents the MSG_MHF_ACQUIRE_CAFE_ITEM
|
// 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.ItemType = bf.ReadUint16()
|
||||||
m.ItemID = bf.ReadUint16()
|
m.ItemID = bf.ReadUint16()
|
||||||
m.Quant = bf.ReadUint16()
|
m.Quant = bf.ReadUint16()
|
||||||
|
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
||||||
m.PointCost = bf.ReadUint32()
|
m.PointCost = bf.ReadUint32()
|
||||||
|
} else {
|
||||||
|
m.PointCost = uint32(bf.ReadUint16())
|
||||||
|
}
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint16()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfAcquireItem represents the MSG_MHF_ACQUIRE_ITEM
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfAcquireItem) Opcode() network.PacketID {
|
func (m *MsgMhfAcquireItem) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,13 @@ func (m *MsgMhfAcquireItem) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfAcquireItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfAcquireTournament represents the MSG_MHF_ACQUIRE_TOURNAMENT
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfAcquireTournament) Opcode() network.PacketID {
|
func (m *MsgMhfAcquireTournament) Opcode() network.PacketID {
|
||||||
@@ -18,7 +21,9 @@ func (m *MsgMhfAcquireTournament) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfAcquireTournament) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
"erupe-ce/network/clientctx"
|
"erupe-ce/network/clientctx"
|
||||||
"erupe-ce/common/byteframe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfApplyCampaign represents the MSG_MHF_APPLY_CAMPAIGN
|
// MsgMhfApplyCampaign represents the MSG_MHF_APPLY_CAMPAIGN
|
||||||
type MsgMhfApplyCampaign struct {
|
type MsgMhfApplyCampaign struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint8
|
Unk0 uint32
|
||||||
Unk1 uint8
|
Unk1 uint16
|
||||||
Unk2 uint16
|
Unk2 []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfApplyCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfApplyCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint8()
|
m.Unk0 = bf.ReadUint32()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Unk1 = bf.ReadUint16()
|
||||||
m.Unk2 = bf.ReadUint16()
|
m.Unk2 = bf.ReadBytes(16)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
func (m *MsgMhfApplyCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfApplyCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
bf.WriteUint32(m.AckHandle)
|
return errors.New("NOT IMPLEMENTED")
|
||||||
bf.WriteUint8(m.Unk0)
|
|
||||||
bf.WriteUint8(m.Unk1)
|
|
||||||
bf.WriteUint16(m.Unk2)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfCaravanMyRank represents the MSG_MHF_CARAVAN_MY_RANK
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfCaravanMyRank) Opcode() network.PacketID {
|
func (m *MsgMhfCaravanMyRank) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,11 @@ func (m *MsgMhfCaravanMyRank) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfCaravanMyRank) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,22 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfCaravanMyScore represents the MSG_MHF_CARAVAN_MY_SCORE
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfCaravanMyScore) Opcode() network.PacketID {
|
func (m *MsgMhfCaravanMyScore) Opcode() network.PacketID {
|
||||||
@@ -18,7 +27,15 @@ func (m *MsgMhfCaravanMyScore) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfCaravanMyScore) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfCaravanRanking represents the MSG_MHF_CARAVAN_RANKING
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfCaravanRanking) Opcode() network.PacketID {
|
func (m *MsgMhfCaravanRanking) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,11 @@ func (m *MsgMhfCaravanRanking) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfCaravanRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfEntryTournament represents the MSG_MHF_ENTRY_TOURNAMENT
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfEntryTournament) Opcode() network.PacketID {
|
func (m *MsgMhfEntryTournament) Opcode() network.PacketID {
|
||||||
@@ -18,7 +22,10 @@ func (m *MsgMhfEntryTournament) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfEntryTournament) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
"erupe-ce/network/clientctx"
|
"erupe-ce/network/clientctx"
|
||||||
"erupe-ce/common/byteframe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfEnumerateCampaign represents the MSG_MHF_ENUMERATE_CAMPAIGN
|
// MsgMhfEnumerateCampaign represents the MSG_MHF_ENUMERATE_CAMPAIGN
|
||||||
type MsgMhfEnumerateCampaign struct {
|
type MsgMhfEnumerateCampaign struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint8
|
Unk0 uint16
|
||||||
Unk1 uint8
|
Unk1 uint16
|
||||||
Unk2 uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfEnumerateCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfEnumerateCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint8()
|
m.Unk0 = bf.ReadUint16()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Unk1 = bf.ReadUint16()
|
||||||
m.Unk2 = bf.ReadUint16()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
func (m *MsgMhfEnumerateCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfEnumerateCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
bf.WriteUint32(m.AckHandle)
|
bf.WriteUint32(m.AckHandle)
|
||||||
bf.WriteUint8(m.Unk0)
|
bf.WriteUint16(m.Unk0)
|
||||||
bf.WriteUint8(m.Unk1)
|
bf.WriteUint16(m.Unk1)
|
||||||
bf.WriteUint16(m.Unk2)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfEnumerateItem represents the MSG_MHF_ENUMERATE_ITEM
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfEnumerateItem) Opcode() network.PacketID {
|
func (m *MsgMhfEnumerateItem) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,11 @@ func (m *MsgMhfEnumerateItem) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfEnumerateItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
@@ -30,7 +31,9 @@ func (m *MsgMhfEnumerateQuest) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
|
|||||||
m.World = bf.ReadUint8()
|
m.World = bf.ReadUint8()
|
||||||
m.Counter = bf.ReadUint16()
|
m.Counter = bf.ReadUint16()
|
||||||
m.Offset = bf.ReadUint16()
|
m.Offset = bf.ReadUint16()
|
||||||
|
if _config.ErupeConfig.RealClientMode > _config.Z1 {
|
||||||
m.Unk4 = bf.ReadUint8()
|
m.Unk4 = bf.ReadUint8()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfEnumerateShop represents the MSG_MHF_ENUMERATE_SHOP
|
// 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.ShopID = bf.ReadUint32()
|
||||||
m.Unk2 = bf.ReadUint16()
|
m.Unk2 = bf.ReadUint16()
|
||||||
m.Unk3 = bf.ReadUint8()
|
m.Unk3 = bf.ReadUint8()
|
||||||
|
if _config.ErupeConfig.RealClientMode >= _config.G2 {
|
||||||
m.Unk4 = bf.ReadUint8()
|
m.Unk4 = bf.ReadUint8()
|
||||||
m.Unk5 = bf.ReadUint32()
|
m.Unk5 = bf.ReadUint32()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetBreakSeibatuLevelReward represents the MSG_MHF_GET_BREAK_SEIBATU_LEVEL_REWARD
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfGetBreakSeibatuLevelReward) Opcode() network.PacketID {
|
func (m *MsgMhfGetBreakSeibatuLevelReward) Opcode() network.PacketID {
|
||||||
@@ -18,7 +22,10 @@ func (m *MsgMhfGetBreakSeibatuLevelReward) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetBreakSeibatuLevelReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,20 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetFixedSeibatuRankingTable represents the MSG_MHF_GET_FIXED_SEIBATU_RANKING_TABLE
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfGetFixedSeibatuRankingTable) Opcode() network.PacketID {
|
func (m *MsgMhfGetFixedSeibatuRankingTable) Opcode() network.PacketID {
|
||||||
@@ -18,7 +25,13 @@ func (m *MsgMhfGetFixedSeibatuRankingTable) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetFixedSeibatuRankingTable) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -11,8 +11,13 @@ import (
|
|||||||
// MsgMhfGetGemInfo represents the MSG_MHF_GET_GEM_INFO
|
// MsgMhfGetGemInfo represents the MSG_MHF_GET_GEM_INFO
|
||||||
type MsgMhfGetGemInfo struct {
|
type MsgMhfGetGemInfo struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk uint32
|
Unk0 uint32
|
||||||
Unk1 []byte
|
Unk1 uint32
|
||||||
|
Unk2 int32
|
||||||
|
Unk3 int32
|
||||||
|
Unk4 int32
|
||||||
|
Unk5 int32
|
||||||
|
Unk6 int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk = bf.ReadUint32()
|
m.Unk0 = bf.ReadUint32()
|
||||||
m.Unk1 = bf.ReadBytes(24)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetNotice represents the MSG_MHF_GET_NOTICE
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfGetNotice) Opcode() network.PacketID {
|
func (m *MsgMhfGetNotice) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,11 @@ func (m *MsgMhfGetNotice) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetNotice) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
// MsgMhfGetRyoudama represents the MSG_MHF_GET_RYOUDAMA
|
// MsgMhfGetRyoudama represents the MSG_MHF_GET_RYOUDAMA
|
||||||
type MsgMhfGetRyoudama struct {
|
type MsgMhfGetRyoudama struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint8
|
Request1 uint8
|
||||||
Unk1 uint8
|
Request2 uint8
|
||||||
GuildID uint32
|
GuildID uint32
|
||||||
Unk3 uint8
|
Unk3 uint8
|
||||||
}
|
}
|
||||||
@@ -25,8 +25,8 @@ func (m *MsgMhfGetRyoudama) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetRyoudama) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetRyoudama) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint8()
|
m.Request1 = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Request2 = bf.ReadUint8()
|
||||||
m.GuildID = bf.ReadUint32()
|
m.GuildID = bf.ReadUint32()
|
||||||
m.Unk3 = bf.ReadUint8()
|
m.Unk3 = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -3,18 +3,17 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetSeibattle represents the MSG_MHF_GET_SEIBATTLE
|
// MsgMhfGetSeibattle represents the MSG_MHF_GET_SEIBATTLE
|
||||||
type MsgMhfGetSeibattle struct {
|
type MsgMhfGetSeibattle struct {
|
||||||
// Communicator type, multi-format. This might be valid for only one type.
|
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint8
|
Unk0 uint8
|
||||||
Unk1 uint8
|
Type uint8
|
||||||
Unk2 uint32 // Some shared ID with MSG_SYS_RECORD_LOG, world ID?
|
GuildID uint32
|
||||||
Unk3 uint8
|
Unk3 uint8
|
||||||
Unk4 uint16
|
Unk4 uint16
|
||||||
}
|
}
|
||||||
@@ -28,8 +27,8 @@ func (m *MsgMhfGetSeibattle) Opcode() network.PacketID {
|
|||||||
func (m *MsgMhfGetSeibattle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetSeibattle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint8()
|
m.Unk0 = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Type = bf.ReadUint8()
|
||||||
m.Unk2 = bf.ReadUint32()
|
m.GuildID = bf.ReadUint32()
|
||||||
m.Unk3 = bf.ReadUint8()
|
m.Unk3 = bf.ReadUint8()
|
||||||
m.Unk4 = bf.ReadUint16()
|
m.Unk4 = bf.ReadUint16()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetSenyuDailyCount represents the MSG_MHF_GET_SENYU_DAILY_COUNT
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfGetSenyuDailyCount) Opcode() network.PacketID {
|
func (m *MsgMhfGetSenyuDailyCount) Opcode() network.PacketID {
|
||||||
@@ -18,7 +20,8 @@ func (m *MsgMhfGetSenyuDailyCount) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetSenyuDailyCount) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,18 +3,19 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetTenrouirai represents the MSG_MHF_GET_TENROUIRAI
|
// MsgMhfGetTenrouirai represents the MSG_MHF_GET_TENROUIRAI
|
||||||
type MsgMhfGetTenrouirai struct {
|
type MsgMhfGetTenrouirai struct {
|
||||||
// Communicator type, multi-format. This might be valid for only one type.
|
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint16
|
Unk0 uint8
|
||||||
Unk1 uint32
|
Unk1 uint8
|
||||||
Unk2 uint16
|
GuildID uint32
|
||||||
|
Unk3 uint8
|
||||||
|
Unk4 uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetTenrouirai) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetTenrouirai) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint32()
|
m.Unk1 = bf.ReadUint8()
|
||||||
m.Unk2 = bf.ReadUint16()
|
m.GuildID = bf.ReadUint32()
|
||||||
|
m.Unk3 = bf.ReadUint8()
|
||||||
|
m.Unk4 = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,17 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetTinyBin represents the MSG_MHF_GET_TINY_BIN
|
// MsgMhfGetTinyBin represents the MSG_MHF_GET_TINY_BIN
|
||||||
type MsgMhfGetTinyBin struct {
|
type MsgMhfGetTinyBin struct {
|
||||||
// Communicator type, multi-format. This might be valid for only one type.
|
// Communicator type, multi-format. This might be valid for only one type.
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint16
|
Unk0 uint8
|
||||||
Unk1 uint8
|
Unk1 uint8
|
||||||
|
Unk2 uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Unk1 = bf.ReadUint8()
|
||||||
|
m.Unk2 = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,19 +8,8 @@ import (
|
|||||||
"erupe-ce/network/clientctx"
|
"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
|
// MsgMhfGetTowerInfo represents the MSG_MHF_GET_TOWER_INFO
|
||||||
type MsgMhfGetTowerInfo struct {
|
type MsgMhfGetTowerInfo struct {
|
||||||
// Communicator type, multi-format. This might be valid for only one type.
|
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
InfoType uint32 // Requested response type
|
InfoType uint32 // Requested response type
|
||||||
Unk0 uint32
|
Unk0 uint32
|
||||||
|
|||||||
@@ -11,33 +11,33 @@ import (
|
|||||||
type OperateGuildAction uint8
|
type OperateGuildAction uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OPERATE_GUILD_DISBAND = 0x01
|
OperateGuildDisband = iota + 1
|
||||||
OPERATE_GUILD_APPLY = 0x02
|
OperateGuildApply
|
||||||
OPERATE_GUILD_LEAVE = 0x03
|
OperateGuildLeave
|
||||||
OPERATE_GUILD_RESIGN = 0x04
|
OperateGuildResign
|
||||||
OPERATE_GUILD_SET_APPLICATION_DENY = 0x05
|
OperateGuildSetApplicationDeny
|
||||||
OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06
|
OperateGuildSetApplicationAllow
|
||||||
OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07
|
OperateGuildSetAvoidLeadershipTrue
|
||||||
OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08
|
OperateGuildSetAvoidLeadershipFalse
|
||||||
OPERATE_GUILD_UPDATE_COMMENT = 0x09
|
OperateGuildUpdateComment
|
||||||
OPERATE_GUILD_DONATE_RANK = 0x0a
|
OperateGuildDonateRank
|
||||||
OPERATE_GUILD_UPDATE_MOTTO = 0x0b
|
OperateGuildUpdateMotto
|
||||||
OPERATE_GUILD_RENAME_PUGI_1 = 0x0c
|
OperateGuildRenamePugi1
|
||||||
OPERATE_GUILD_RENAME_PUGI_2 = 0x0d
|
OperateGuildRenamePugi2
|
||||||
OPERATE_GUILD_RENAME_PUGI_3 = 0x0e
|
OperateGuildRenamePugi3
|
||||||
OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f
|
OperateGuildChangePugi1
|
||||||
OPERATE_GUILD_CHANGE_PUGI_2 = 0x10
|
OperateGuildChangePugi2
|
||||||
OPERATE_GUILD_CHANGE_PUGI_3 = 0x11
|
OperateGuildChangePugi3
|
||||||
OPERATE_GUILD_UNLOCK_OUTFIT = 0x12
|
OperateGuildUnlockOutfit
|
||||||
// 0x13 Unk
|
OperateGuildDonateRoom
|
||||||
// 0x14 Unk
|
OperateGuildGraduateRookie
|
||||||
OPERATE_GUILD_DONATE_EVENT = 0x15
|
OperateGuildDonateEvent
|
||||||
OPERATE_GUILD_EVENT_EXCHANGE = 0x16
|
OperateGuildEventExchange
|
||||||
// 0x17 Unk
|
OperateGuildUnknown // I don't think this op exists
|
||||||
// 0x18 Unk
|
OperateGuildGraduateReturn
|
||||||
OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19
|
OperateGuildChangeDivaPugi1
|
||||||
OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a
|
OperateGuildChangeDivaPugi2
|
||||||
OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b
|
OperateGuildChangeDivaPugi3
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD
|
// MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPostBoostTimeLimit represents the MSG_MHF_POST_BOOST_TIME_LIMIT
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfPostBoostTimeLimit) Opcode() network.PacketID {
|
func (m *MsgMhfPostBoostTimeLimit) Opcode() network.PacketID {
|
||||||
@@ -18,7 +21,9 @@ func (m *MsgMhfPostBoostTimeLimit) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostBoostTimeLimit) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,22 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPostGemInfo represents the MSG_MHF_POST_GEM_INFO
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfPostGemInfo) Opcode() network.PacketID {
|
func (m *MsgMhfPostGemInfo) Opcode() network.PacketID {
|
||||||
@@ -18,7 +27,15 @@ func (m *MsgMhfPostGemInfo) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,19 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPostNotice represents the MSG_MHF_POST_NOTICE
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfPostNotice) Opcode() network.PacketID {
|
func (m *MsgMhfPostNotice) Opcode() network.PacketID {
|
||||||
@@ -18,7 +24,12 @@ func (m *MsgMhfPostNotice) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostNotice) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,20 +3,32 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPostTenrouirai represents the MSG_MHF_POST_TENROUIRAI
|
// MsgMhfPostTenrouirai represents the MSG_MHF_POST_TENROUIRAI
|
||||||
type MsgMhfPostTenrouirai struct{
|
type MsgMhfPostTenrouirai struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint16
|
Unk0 uint8
|
||||||
Unk1 uint32
|
Op uint8
|
||||||
Unk2 uint32
|
GuildID uint32
|
||||||
Unk3 uint32
|
Unk1 uint8
|
||||||
Unk4 uint32
|
|
||||||
Unk5 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.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostTenrouirai) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPostTenrouirai) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint32()
|
m.Op = bf.ReadUint8()
|
||||||
m.Unk2 = bf.ReadUint32()
|
m.GuildID = bf.ReadUint32()
|
||||||
m.Unk3 = bf.ReadUint32()
|
m.Unk1 = bf.ReadUint8()
|
||||||
m.Unk4 = bf.ReadUint32()
|
|
||||||
m.Unk5 = 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import (
|
|||||||
// MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN
|
// MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN
|
||||||
type MsgMhfPostTinyBin struct {
|
type MsgMhfPostTinyBin struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint16
|
Unk0 uint8
|
||||||
Unk1 uint8
|
Unk1 uint8
|
||||||
Unk2 uint8
|
Unk2 uint8
|
||||||
|
Unk3 uint8
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,9 +26,10 @@ func (m *MsgMhfPostTinyBin) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Unk1 = bf.ReadUint8()
|
||||||
m.Unk2 = bf.ReadUint8()
|
m.Unk2 = bf.ReadUint8()
|
||||||
|
m.Unk3 = bf.ReadUint8()
|
||||||
m.Data = bf.ReadBytes(uint(bf.ReadUint16()))
|
m.Data = bf.ReadBytes(uint(bf.ReadUint16()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,24 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPostTowerInfo represents the MSG_MHF_POST_TOWER_INFO
|
// MsgMhfPostTowerInfo represents the MSG_MHF_POST_TOWER_INFO
|
||||||
type MsgMhfPostTowerInfo struct {
|
type MsgMhfPostTowerInfo struct {
|
||||||
// Communicator type, multi-format. This might be valid for only one type.
|
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint32
|
InfoType uint32
|
||||||
Unk1 uint32
|
Unk1 uint32
|
||||||
Unk2 uint32
|
Skill int32
|
||||||
Unk3 uint32
|
TR int32
|
||||||
Unk4 uint32
|
TRP int32
|
||||||
Unk5 uint32
|
Cost int32
|
||||||
Unk6 uint32
|
Unk6 int32
|
||||||
Unk7 uint32
|
Unk7 int32
|
||||||
Unk8 uint32
|
Block1 int32
|
||||||
Unk9 uint32
|
Unk9 int64
|
||||||
Unk10 uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostTowerInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPostTowerInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint32()
|
m.InfoType = bf.ReadUint32()
|
||||||
m.Unk1 = bf.ReadUint32()
|
m.Unk1 = bf.ReadUint32()
|
||||||
m.Unk2 = bf.ReadUint32()
|
m.Skill = bf.ReadInt32()
|
||||||
m.Unk3 = bf.ReadUint32()
|
m.TR = bf.ReadInt32()
|
||||||
m.Unk4 = bf.ReadUint32()
|
m.TRP = bf.ReadInt32()
|
||||||
m.Unk5 = bf.ReadUint32()
|
m.Cost = bf.ReadInt32()
|
||||||
m.Unk6 = bf.ReadUint32()
|
m.Unk6 = bf.ReadInt32()
|
||||||
m.Unk7 = bf.ReadUint32()
|
m.Unk7 = bf.ReadInt32()
|
||||||
m.Unk8 = bf.ReadUint32()
|
m.Block1 = bf.ReadInt32()
|
||||||
m.Unk9 = bf.ReadUint32()
|
m.Unk9 = bf.ReadInt64()
|
||||||
m.Unk10 = bf.ReadUint32()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ type MsgMhfPresentBox struct {
|
|||||||
Unk4 uint32
|
Unk4 uint32
|
||||||
Unk5 uint32
|
Unk5 uint32
|
||||||
Unk6 uint32
|
Unk6 uint32
|
||||||
Unk7 uint32
|
Unk7 []uint32
|
||||||
Unk8 uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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.Unk4 = bf.ReadUint32()
|
||||||
m.Unk5 = bf.ReadUint32()
|
m.Unk5 = bf.ReadUint32()
|
||||||
m.Unk6 = bf.ReadUint32()
|
m.Unk6 = bf.ReadUint32()
|
||||||
m.Unk7 = bf.ReadUint32()
|
for i := uint32(0); i < m.Unk2; i++ {
|
||||||
m.Unk8 = bf.ReadUint32()
|
m.Unk7 = append(m.Unk7, bf.ReadUint32())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfReadBeatLevelAllRanking represents the MSG_MHF_READ_BEAT_LEVEL_ALL_RANKING
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfReadBeatLevelAllRanking) Opcode() network.PacketID {
|
func (m *MsgMhfReadBeatLevelAllRanking) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,11 @@ func (m *MsgMhfReadBeatLevelAllRanking) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfReadBeatLevelAllRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfReadBeatLevelMyRanking represents the MSG_MHF_READ_BEAT_LEVEL_MY_RANKING
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfReadBeatLevelMyRanking) Opcode() network.PacketID {
|
func (m *MsgMhfReadBeatLevelMyRanking) Opcode() network.PacketID {
|
||||||
@@ -18,7 +23,13 @@ func (m *MsgMhfReadBeatLevelMyRanking) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfReadBeatLevelMyRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfReadLastWeekBeatRanking represents the MSG_MHF_READ_LAST_WEEK_BEAT_RANKING
|
// 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.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfReadLastWeekBeatRanking) Opcode() network.PacketID {
|
func (m *MsgMhfReadLastWeekBeatRanking) Opcode() network.PacketID {
|
||||||
@@ -18,7 +22,10 @@ func (m *MsgMhfReadLastWeekBeatRanking) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfReadLastWeekBeatRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
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.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfSavedata represents the MSG_MHF_SAVEDATA
|
// 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.AllocMemSize = bf.ReadUint32()
|
||||||
m.SaveType = bf.ReadUint8()
|
m.SaveType = bf.ReadUint8()
|
||||||
m.Unk1 = bf.ReadUint32()
|
m.Unk1 = bf.ReadUint32()
|
||||||
|
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
||||||
m.DataSize = bf.ReadUint32()
|
m.DataSize = bf.ReadUint32()
|
||||||
|
}
|
||||||
if m.DataSize == 0 { // seems to be used when DataSize = 0 rather than on savetype?
|
if m.DataSize == 0 { // seems to be used when DataSize = 0 rather than on savetype?
|
||||||
m.RawDataPayload = bf.ReadBytes(uint(m.AllocMemSize))
|
m.RawDataPayload = bf.ReadBytes(uint(m.AllocMemSize))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,16 +3,22 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfSetCaAchievementHist represents the MSG_MHF_SET_CA_ACHIEVEMENT_HIST
|
type CaAchievementHist struct {
|
||||||
type MsgMhfSetCaAchievementHist struct{
|
|
||||||
AckHandle uint32
|
|
||||||
Unk0 uint32
|
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.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfSetCaAchievementHist) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfSetCaAchievementHist) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint32()
|
m.Unk0 = bf.ReadUint16()
|
||||||
m.Unk1 = bf.ReadUint32()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ package mhfpacket
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfSexChanger represents the MSG_MHF_SEX_CHANGER
|
// MsgMhfSexChanger represents the MSG_MHF_SEX_CHANGER
|
||||||
type MsgMhfSexChanger struct {
|
type MsgMhfSexChanger struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Gender uint8
|
Gender uint8
|
||||||
|
Unk0 uint8
|
||||||
|
Unk1 uint8
|
||||||
|
Unk2 uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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 {
|
func (m *MsgMhfSexChanger) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Gender = bf.ReadUint8()
|
m.Gender = bf.ReadUint8()
|
||||||
|
m.Unk0 = bf.ReadUint8()
|
||||||
|
m.Unk1 = bf.ReadUint8()
|
||||||
|
m.Unk2 = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
@@ -34,12 +35,14 @@ func (m *MsgMhfStampcardStamp) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
|
|||||||
m.GR = bf.ReadUint16()
|
m.GR = bf.ReadUint16()
|
||||||
m.Stamps = bf.ReadUint16()
|
m.Stamps = bf.ReadUint16()
|
||||||
_ = bf.ReadUint16()
|
_ = bf.ReadUint16()
|
||||||
|
if _config.ErupeConfig.RealClientMode > _config.Z1 {
|
||||||
m.Reward1 = uint16(bf.ReadUint32())
|
m.Reward1 = uint16(bf.ReadUint32())
|
||||||
m.Reward2 = uint16(bf.ReadUint32())
|
m.Reward2 = uint16(bf.ReadUint32())
|
||||||
m.Item1 = uint16(bf.ReadUint32())
|
m.Item1 = uint16(bf.ReadUint32())
|
||||||
m.Item2 = uint16(bf.ReadUint32())
|
m.Item2 = uint16(bf.ReadUint32())
|
||||||
m.Quantity1 = uint16(bf.ReadUint32())
|
m.Quantity1 = uint16(bf.ReadUint32())
|
||||||
m.Quantity2 = uint16(bf.ReadUint32())
|
m.Quantity2 = uint16(bf.ReadUint32())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"erupe-ce/network/clientctx"
|
"erupe-ce/network/clientctx"
|
||||||
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfStateCampaign represents the MSG_MHF_STATE_CAMPAIGN
|
// MsgMhfStateCampaign represents the MSG_MHF_STATE_CAMPAIGN
|
||||||
type MsgMhfStateCampaign struct {
|
type MsgMhfStateCampaign struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint8
|
CampaignID uint32
|
||||||
Unk1 uint8
|
Unk1 uint16
|
||||||
Unk2 uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// 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
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfStateCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfStateCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint8()
|
m.CampaignID = bf.ReadUint32()
|
||||||
m.Unk1 = bf.ReadUint8()
|
m.Unk1 = bf.ReadUint16()
|
||||||
m.Unk2 = bf.ReadUint16()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
func (m *MsgMhfStateCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfStateCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
bf.WriteUint32(m.AckHandle)
|
return errors.New("NOT IMPLEMENTED")
|
||||||
bf.WriteUint8(m.Unk0)
|
|
||||||
bf.WriteUint8(m.Unk1)
|
|
||||||
bf.WriteUint16(m.Unk2)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,8 @@ type MsgMhfUpdateBeatLevel struct {
|
|||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk1 uint32
|
Unk1 uint32
|
||||||
Unk2 uint32
|
Unk2 uint32
|
||||||
MonsterData []byte
|
Data1 []int32
|
||||||
Unk3 uint8
|
Data2 []int32
|
||||||
Unk4 uint32
|
|
||||||
Unk5 uint16
|
|
||||||
Unk6 uint8
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -31,11 +27,12 @@ func (m *MsgMhfUpdateBeatLevel) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl
|
|||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk1 = bf.ReadUint32()
|
m.Unk1 = bf.ReadUint32()
|
||||||
m.Unk2 = bf.ReadUint32()
|
m.Unk2 = bf.ReadUint32()
|
||||||
m.MonsterData = bf.ReadBytes(uint(120))
|
for i := 0; i < 16; i++ {
|
||||||
m.Unk3 = bf.ReadUint8()
|
m.Data1 = append(m.Data1, bf.ReadInt32())
|
||||||
m.Unk4 = bf.ReadUint32()
|
}
|
||||||
m.Unk5 = bf.ReadUint16()
|
for i := 0; i < 16; i++ {
|
||||||
m.Unk6 = bf.ReadUint8()
|
m.Data2 = append(m.Data2, bf.ReadInt32())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
|
||||||
"erupe-ce/common/bfutil"
|
"erupe-ce/common/bfutil"
|
||||||
|
"erupe-ce/common/byteframe"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
"erupe-ce/network/clientctx"
|
"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 {
|
func (m *MsgSysCreateAcquireSemaphore) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint16()
|
||||||
|
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
||||||
m.PlayerCount = bf.ReadUint8()
|
m.PlayerCount = bf.ReadUint8()
|
||||||
fmt.Printf("PLAYER COUNT :: %d", m.PlayerCount)
|
}
|
||||||
SemaphoreIDLength := bf.ReadUint8()
|
SemaphoreIDLength := bf.ReadUint8()
|
||||||
m.SemaphoreID = string(bfutil.UpToNull(bf.ReadBytes(uint(SemaphoreIDLength))))
|
m.SemaphoreID = string(bfutil.UpToNull(bf.ReadBytes(uint(SemaphoreIDLength))))
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mhfpacket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
@@ -37,12 +38,16 @@ func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client
|
|||||||
m.EntryCount = bf.ReadUint16()
|
m.EntryCount = bf.ReadUint16()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Unk0 = bf.ReadUint16()
|
||||||
|
|
||||||
|
values := 15
|
||||||
|
if _config.ErupeConfig.RealClientMode <= _config.F5 {
|
||||||
|
values = 7
|
||||||
|
}
|
||||||
for i := 0; i < int(m.EntryCount); i++ {
|
for i := 0; i < int(m.EntryCount); i++ {
|
||||||
e := &TerminalLogEntry{}
|
e := &TerminalLogEntry{}
|
||||||
e.Index = bf.ReadUint32()
|
e.Index = bf.ReadUint32()
|
||||||
e.Type1 = bf.ReadUint8()
|
e.Type1 = bf.ReadUint8()
|
||||||
e.Type2 = 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())
|
e.Data = append(e.Data, bf.ReadInt16())
|
||||||
}
|
}
|
||||||
m.Entries = append(m.Entries, e)
|
m.Entries = append(m.Entries, e)
|
||||||
|
|||||||
29
patch-schema/tower.sql
Normal file
29
patch-schema/tower.sql
Normal file
@@ -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;
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"erupe-ce/common/mhfcourse"
|
"erupe-ce/common/mhfcourse"
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@@ -27,15 +28,16 @@ func stubEnumerateNoResults(s *Session, ackHandle uint32) {
|
|||||||
doAckBufSucceed(s, ackHandle, enumBf.Data())
|
doAckBufSucceed(s, ackHandle, enumBf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary function to just return no results for many MSG_MHF_GET* packets.
|
func doAckEarthSucceed(s *Session, ackHandle uint32, data []*byteframe.ByteFrame) {
|
||||||
func stubGetNoResults(s *Session, ackHandle uint32) {
|
bf := byteframe.NewByteFrame()
|
||||||
resp := byteframe.NewByteFrame()
|
bf.WriteUint32(uint32(s.server.erupeConfig.DevModeOptions.EarthIDOverride))
|
||||||
resp.WriteUint32(0x0A218EAD) // Unk shared ID. Sent in response of MSG_MHF_GET_TOWER_INFO, MSG_MHF_GET_PAPER_DATA etc. (World ID?)
|
bf.WriteUint32(0)
|
||||||
resp.WriteUint32(0) // Unk
|
bf.WriteUint32(0)
|
||||||
resp.WriteUint32(0) // Unk
|
bf.WriteUint32(uint32(len(data)))
|
||||||
resp.WriteUint32(0) // Entry count
|
for i := range data {
|
||||||
|
bf.WriteBytes(data[i].Data())
|
||||||
doAckBufSucceed(s, ackHandle, resp.Data())
|
}
|
||||||
|
doAckBufSucceed(s, ackHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func doAckBufSucceed(s *Session, ackHandle uint32, data []byte) {
|
func doAckBufSucceed(s *Session, ackHandle uint32, data []byte) {
|
||||||
@@ -245,7 +247,7 @@ func logoutPlayer(s *Session) {
|
|||||||
removeSessionFromStage(s)
|
removeSessionFromStage(s)
|
||||||
|
|
||||||
saveData, err := GetCharacterSaveData(s, s.charID)
|
saveData, err := GetCharacterSaveData(s, s.charID)
|
||||||
if err != nil {
|
if err != nil || saveData == nil {
|
||||||
s.logger.Error("Failed to get savedata")
|
s.logger.Error("Failed to get savedata")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -446,48 +448,110 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 4: // Find Party
|
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)
|
bf := byteframe.NewByteFrameFromBytes(pkt.MessageData)
|
||||||
setting := bf.ReadUint8()
|
numParams := int(bf.ReadUint8())
|
||||||
maxResults := bf.ReadUint16()
|
maxResults := bf.ReadUint16()
|
||||||
bf.Seek(2, 1)
|
for i := 0; i < numParams; i++ {
|
||||||
partyType := bf.ReadUint16()
|
switch bf.ReadUint8() {
|
||||||
rankRestriction := uint16(0)
|
case 0:
|
||||||
if setting >= 2 {
|
values := int(bf.ReadUint8())
|
||||||
bf.Seek(2, 1)
|
for i := 0; i < values; i++ {
|
||||||
rankRestriction = bf.ReadUint16()
|
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
|
||||||
}
|
findPartyParams.RankRestriction = bf.ReadUint16()
|
||||||
targets := make([]uint16, 4)
|
} else {
|
||||||
if setting >= 3 {
|
findPartyParams.RankRestriction = uint16(bf.ReadInt8())
|
||||||
bf.Seek(1, 1)
|
|
||||||
lenTargets := int(bf.ReadUint8())
|
|
||||||
for i := 0; i < lenTargets; i++ {
|
|
||||||
targets[i] = bf.ReadUint16()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var stagePrefix string
|
case 1:
|
||||||
switch partyType {
|
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
|
case 0: // Public Bar
|
||||||
stagePrefix = "sl2Ls210"
|
findPartyParams.StagePrefix = "sl2Ls210"
|
||||||
case 1: // Tokotoko Partnya
|
case 1: // Tokotoko Partnya
|
||||||
stagePrefix = "sl2Ls463"
|
findPartyParams.StagePrefix = "sl2Ls463"
|
||||||
case 2: // Hunting Prowess Match
|
case 2: // Hunting Prowess Match
|
||||||
stagePrefix = "sl2Ls286"
|
findPartyParams.StagePrefix = "sl2Ls286"
|
||||||
case 3: // Volpakkun Together
|
case 3: // Volpakkun Together
|
||||||
stagePrefix = "sl2Ls465"
|
findPartyParams.StagePrefix = "sl2Ls465"
|
||||||
case 5: // Quick Party
|
case 5: // Quick Party
|
||||||
// Unk
|
// 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()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, c := range s.server.Channels {
|
for _, c := range s.server.Channels {
|
||||||
for _, stage := range c.stages {
|
for _, stage := range c.stages {
|
||||||
if count == maxResults {
|
if count == maxResults {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(stage.id, stagePrefix) {
|
if strings.HasPrefix(stage.id, findPartyParams.StagePrefix) {
|
||||||
sb3 := byteframe.NewByteFrameFromBytes(stage.rawBinaryData[stageBinaryKey{1, 3}])
|
sb3 := byteframe.NewByteFrameFromBytes(stage.rawBinaryData[stageBinaryKey{1, 3}])
|
||||||
sb3.Seek(4, 0)
|
sb3.Seek(4, 0)
|
||||||
stageRankRestriction := sb3.ReadUint16()
|
stageRankRestriction := sb3.ReadUint16()
|
||||||
stageTarget := 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
|
continue
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
@@ -551,10 +615,6 @@ func handleMsgSysInfokyserver(s *Session, p mhfpacket.MHFPacket) {}
|
|||||||
|
|
||||||
func handleMsgMhfGetCaUniqueID(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) {
|
func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfTransferItem)
|
pkt := p.(*mhfpacket.MsgMhfTransferItem)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
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 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 handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetEarthStatus)
|
pkt := p.(*mhfpacket.MsgMhfGetEarthStatus)
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
// TODO(Andoryuuta): Track down format for this data,
|
bf.WriteUint32(uint32(TimeWeekStart().Add(time.Hour * -24).Unix())) // Start
|
||||||
// it can somehow be parsed as 8*uint32 chunks if the header is right.
|
bf.WriteUint32(uint32(TimeWeekNext().Add(time.Hour * 24).Unix())) // End
|
||||||
/*
|
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthStatusOverride)
|
||||||
BEFORE ack-refactor:
|
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthIDOverride)
|
||||||
resp := byteframe.NewByteFrame()
|
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthMonsterOverride)
|
||||||
resp.WriteUint32(0)
|
bf.WriteInt32(0)
|
||||||
resp.WriteUint32(0)
|
bf.WriteInt32(0)
|
||||||
|
bf.WriteInt32(0)
|
||||||
s.QueueAck(pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
*/
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetEarthValue(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetEarthValue(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetEarthValue)
|
pkt := p.(*mhfpacket.MsgMhfGetEarthValue)
|
||||||
var earthValues []struct{ Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32 }
|
type EarthValues struct {
|
||||||
if pkt.ReqType == 3 {
|
Value []uint32
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
} else if pkt.ReqType == 2 {
|
|
||||||
earthValues = []struct {
|
var earthValues []EarthValues
|
||||||
Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32
|
switch pkt.ReqType {
|
||||||
}{
|
case 1:
|
||||||
// JP response was empty
|
earthValues = []EarthValues{
|
||||||
{
|
{[]uint32{1, 312, 0, 0, 0, 0}},
|
||||||
Unk0: 0x01,
|
{[]uint32{2, 99, 0, 0, 0, 0}},
|
||||||
Unk1: 0x168B,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Unk0: 0x02,
|
|
||||||
Unk1: 0x0737,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
} else if pkt.ReqType == 1 {
|
case 2:
|
||||||
earthValues = []struct {
|
earthValues = []EarthValues{
|
||||||
Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32
|
{[]uint32{1, 5771, 0, 0, 0, 0}},
|
||||||
}{
|
{[]uint32{2, 1847, 0, 0, 0, 0}},
|
||||||
// JP simply sent 01 and 02 respectively
|
}
|
||||||
{
|
case 3:
|
||||||
Unk0: 0x01,
|
earthValues = []EarthValues{
|
||||||
Unk1: 0x0138,
|
{[]uint32{1001, 36, 0, 0, 0, 0}},
|
||||||
},
|
{[]uint32{9001, 3, 0, 0, 0, 0}},
|
||||||
{
|
{[]uint32{9002, 10, 300, 0, 0, 0}},
|
||||||
Unk0: 0x02,
|
|
||||||
Unk1: 0x63,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := byteframe.NewByteFrame()
|
var data []*byteframe.ByteFrame
|
||||||
resp.WriteUint32(0x0A218EAD) // Unk shared ID. Sent in response of MSG_MHF_GET_TOWER_INFO, MSG_MHF_GET_PAPER_DATA etc.
|
for _, i := range earthValues {
|
||||||
resp.WriteUint32(0) // Unk
|
bf := byteframe.NewByteFrame()
|
||||||
resp.WriteUint32(0) // Unk
|
for _, j := range i.Value {
|
||||||
resp.WriteUint32(uint32(len(earthValues))) // value count
|
bf.WriteUint32(j)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
data = append(data, bf)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
}
|
||||||
|
doAckEarthSucceed(s, pkt.AckHandle, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfDebugPostValue(s *Session, p mhfpacket.MHFPacket) {}
|
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 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) {
|
func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetSeibattle)
|
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) {}
|
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|||||||
@@ -270,6 +270,12 @@ func handleMsgMhfPostBoostTimeQuestReturn(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,173 @@
|
|||||||
package channelserver
|
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) {
|
func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateCampaign)
|
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) {
|
func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfStateCampaign)
|
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) {
|
func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfApplyCampaign)
|
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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,73 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/common/stringsupport"
|
||||||
"erupe-ce/network/mhfpacket"
|
"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) {
|
func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetRyoudama)
|
pkt := p.(*mhfpacket.MsgMhfGetRyoudama)
|
||||||
// likely guild related
|
var data []*byteframe.ByteFrame
|
||||||
// REQ: 00 04 13 53 8F 18 00
|
ryoudama := Ryoudama{Score: []int32{0}}
|
||||||
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 01 FE 4E
|
switch pkt.Request2 {
|
||||||
// REQ: 00 06 13 53 8F 18 00
|
case 4:
|
||||||
// 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
|
for _, score := range ryoudama.Score {
|
||||||
// REQ: 00 05 13 53 8F 18 00
|
bf := byteframe.NewByteFrame()
|
||||||
// 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
|
bf.WriteInt32(score)
|
||||||
data, _ := hex.DecodeString("0A218EAD0000000000000000000000010000000000000000")
|
data = append(data, bf)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
}
|
||||||
|
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) {}
|
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))
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,16 +35,16 @@ const (
|
|||||||
BroadcastTypeWorld = 0x0a
|
BroadcastTypeWorld = 0x0a
|
||||||
)
|
)
|
||||||
|
|
||||||
var commands map[string]config.Command
|
var commands map[string]_config.Command
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
commands = make(map[string]config.Command)
|
commands = make(map[string]_config.Command)
|
||||||
zapConfig := zap.NewDevelopmentConfig()
|
zapConfig := zap.NewDevelopmentConfig()
|
||||||
zapConfig.DisableCaller = true
|
zapConfig.DisableCaller = true
|
||||||
zapLogger, _ := zapConfig.Build()
|
zapLogger, _ := zapConfig.Build()
|
||||||
defer zapLogger.Sync()
|
defer zapLogger.Sync()
|
||||||
logger := zapLogger.Named("commands")
|
logger := zapLogger.Named("commands")
|
||||||
cmds := config.ErupeConfig.Commands
|
cmds := _config.ErupeConfig.Commands
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
commands[cmd.Name] = cmd
|
commands[cmd.Name] = cmd
|
||||||
if cmd.Enabled {
|
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))
|
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 _, course := range mhfcourse.Courses() {
|
||||||
for _, alias := range course.Aliases() {
|
for _, alias := range course.Aliases() {
|
||||||
if strings.ToLower(name) == strings.ToLower(alias) {
|
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
|
var delta, rightsInt uint32
|
||||||
if mhfcourse.CourseExists(course.ID, s.courses) {
|
if mhfcourse.CourseExists(course.ID, s.courses) {
|
||||||
ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool {
|
ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool {
|
||||||
|
|||||||
@@ -5,33 +5,36 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"erupe-ce/common/bfutil"
|
"erupe-ce/common/bfutil"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/server/channelserver/compression/nullcomp"
|
"erupe-ce/server/channelserver/compression/nullcomp"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SavePointer int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pointerGender = 0x51 // +1
|
pGender = iota // +1
|
||||||
pointerRP = 0x22D16 // +2
|
pRP // +2
|
||||||
pointerHouseTier = 0x1FB6C // +5
|
pHouseTier // +5
|
||||||
pointerHouseData = 0x1FE01 // +195
|
pHouseData // +195
|
||||||
pointerBookshelfData = 0x22298 // +5576
|
pBookshelfData // +5576
|
||||||
// Gallery data also exists at 0x21578, is this the contest submission?
|
pGalleryData // +1748
|
||||||
pointerGalleryData = 0x22320 // +1748
|
pToreData // +240
|
||||||
pointerToreData = 0x1FCB4 // +240
|
pGardenData // +68
|
||||||
pointerGardenData = 0x22C58 // +68
|
pWeaponType // +1
|
||||||
pointerWeaponType = 0x1F715 // +1
|
pWeaponID // +2
|
||||||
pointerWeaponID = 0x1F60A // +2
|
pHRP // +2
|
||||||
pointerHRP = 0x1FDF6 // +2
|
pGRP // +4
|
||||||
pointerGRP = 0x1FDFC // +4
|
pKQF // +8
|
||||||
pointerKQF = 0x23D20 // +8
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CharacterSaveData struct {
|
type CharacterSaveData struct {
|
||||||
CharID uint32
|
CharID uint32
|
||||||
Name string
|
Name string
|
||||||
IsNewCharacter bool
|
IsNewCharacter bool
|
||||||
|
Pointers map[SavePointer]int
|
||||||
|
|
||||||
Gender bool
|
Gender bool
|
||||||
RP uint16
|
RP uint16
|
||||||
@@ -51,6 +54,39 @@ type CharacterSaveData struct {
|
|||||||
decompSave []byte
|
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) {
|
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)
|
result, err := s.server.db.Query("SELECT id, savedata, is_new_character, name FROM characters WHERE id = $1", charID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,7 +100,9 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
saveData := &CharacterSaveData{}
|
saveData := &CharacterSaveData{
|
||||||
|
Pointers: getPointers(),
|
||||||
|
}
|
||||||
err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name)
|
err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to scan savedata", zap.Error(err), zap.Uint32("charID", charID))
|
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()
|
save.updateSaveDataWithStruct()
|
||||||
|
|
||||||
|
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
||||||
err := save.Compress()
|
err := save.Compress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to compress savedata", zap.Error(err))
|
s.logger.Error("Failed to compress savedata", zap.Error(err))
|
||||||
return
|
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)
|
`, save.compSave, save.HRP, save.GR, save.Gender, save.WeaponType, save.WeaponID, save.CharID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID))
|
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() {
|
func (save *CharacterSaveData) updateSaveDataWithStruct() {
|
||||||
rpBytes := make([]byte, 2)
|
rpBytes := make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(rpBytes, save.RP)
|
binary.LittleEndian.PutUint16(rpBytes, save.RP)
|
||||||
copy(save.decompSave[pointerRP:pointerRP+2], rpBytes)
|
if _config.ErupeConfig.RealClientMode >= _config.G10 {
|
||||||
copy(save.decompSave[pointerKQF:pointerKQF+8], save.KQF)
|
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
|
// This will update the save struct with the values stored in the character save
|
||||||
func (save *CharacterSaveData) updateStructWithSaveData() {
|
func (save *CharacterSaveData) updateStructWithSaveData() {
|
||||||
save.Name = stringsupport.SJISToUTF8(bfutil.UpToNull(save.decompSave[88:100]))
|
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
|
save.Gender = true
|
||||||
} else {
|
} else {
|
||||||
save.Gender = false
|
save.Gender = false
|
||||||
}
|
}
|
||||||
if !save.IsNewCharacter {
|
if !save.IsNewCharacter {
|
||||||
save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRP : pointerRP+2])
|
if _config.ErupeConfig.RealClientMode >= _config.G10 {
|
||||||
save.HouseTier = save.decompSave[pointerHouseTier : pointerHouseTier+5]
|
save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2])
|
||||||
save.HouseData = save.decompSave[pointerHouseData : pointerHouseData+195]
|
save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5]
|
||||||
save.BookshelfData = save.decompSave[pointerBookshelfData : pointerBookshelfData+5576]
|
save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195]
|
||||||
save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748]
|
save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+5576]
|
||||||
save.ToreData = save.decompSave[pointerToreData : pointerToreData+240]
|
save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748]
|
||||||
save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68]
|
save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240]
|
||||||
save.WeaponType = save.decompSave[pointerWeaponType]
|
save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68]
|
||||||
save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2])
|
save.WeaponType = save.decompSave[save.Pointers[pWeaponType]]
|
||||||
save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2])
|
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) {
|
if save.HRP == uint16(999) {
|
||||||
save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4]))
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSexChanger)
|
pkt := p.(*mhfpacket.MsgMhfSexChanger)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,6 +3,7 @@ package channelserver
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
@@ -71,7 +72,11 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
var timestamps []uint32
|
var timestamps []uint32
|
||||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DivaEvent >= 0 {
|
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DivaEvent >= 0 {
|
||||||
if s.server.erupeConfig.DevModeOptions.DivaEvent == 0 {
|
if s.server.erupeConfig.DevModeOptions.DivaEvent == 0 {
|
||||||
|
if s.server.erupeConfig.RealClientMode <= _config.Z1 {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 32))
|
||||||
|
} else {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 36))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 36))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
timestamps = generateDivaTimestamps(s, uint32(s.server.erupeConfig.DevModeOptions.DivaEvent), true)
|
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)
|
timestamps = generateDivaTimestamps(s, start, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.server.erupeConfig.RealClientMode <= _config.Z1 {
|
||||||
bf.WriteUint32(id)
|
bf.WriteUint32(id)
|
||||||
for _, timestamp := range timestamps {
|
}
|
||||||
bf.WriteUint32(timestamp)
|
for i := range timestamps {
|
||||||
|
bf.WriteUint32(timestamps[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint16(0x19) // Unk 00011001
|
bf.WriteUint16(0x19) // Unk 00011001
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package channelserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"erupe-ce/common/token"
|
"erupe-ce/common/token"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"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) {
|
func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateEvent)
|
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 {
|
type activeFeature struct {
|
||||||
@@ -90,14 +123,24 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateFeatureWeapons(count int) activeFeature {
|
func generateFeatureWeapons(count int) activeFeature {
|
||||||
if count > 14 {
|
max := 14
|
||||||
count = 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)
|
nums := make([]int, 0)
|
||||||
var result int
|
var result int
|
||||||
for len(nums) < count {
|
for len(nums) < count {
|
||||||
rng := token.RNG()
|
rng := token.RNG()
|
||||||
num := rng.Intn(14)
|
num := rng.Intn(max)
|
||||||
exist := false
|
exist := false
|
||||||
for _, v := range nums {
|
for _, v := range nums {
|
||||||
if v == num {
|
if v == num {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/common/token"
|
"erupe-ce/common/token"
|
||||||
@@ -140,13 +139,26 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
|||||||
return timestamps
|
return timestamps
|
||||||
}
|
}
|
||||||
|
|
||||||
type Trial struct {
|
type FestaTrial struct {
|
||||||
ID uint32 `db:"id"`
|
ID uint32 `db:"id"`
|
||||||
Objective uint8 `db:"objective"`
|
Objective uint16 `db:"objective"`
|
||||||
GoalID uint32 `db:"goal_id"`
|
GoalID uint32 `db:"goal_id"`
|
||||||
TimesReq uint16 `db:"times_req"`
|
TimesReq uint16 `db:"times_req"`
|
||||||
Locale uint16 `db:"locale_req"`
|
Locale uint16 `db:"locale_req"`
|
||||||
Reward uint16 `db:"reward"`
|
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) {
|
func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -190,36 +202,71 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(blueSouls)
|
bf.WriteUint32(blueSouls)
|
||||||
bf.WriteUint32(redSouls)
|
bf.WriteUint32(redSouls)
|
||||||
|
|
||||||
|
var trials []FestaTrial
|
||||||
|
var trial FestaTrial
|
||||||
rows, _ = s.server.db.Queryx("SELECT * FROM festa_trials")
|
rows, _ = s.server.db.Queryx("SELECT * FROM festa_trials")
|
||||||
trialData := byteframe.NewByteFrame()
|
|
||||||
var count uint16
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
trial := &Trial{}
|
|
||||||
err := rows.StructScan(&trial)
|
err := rows.StructScan(&trial)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
count++
|
trials = append(trials, trial)
|
||||||
trialData.WriteUint32(trial.ID)
|
}
|
||||||
trialData.WriteUint8(0) // Unk
|
bf.WriteUint16(uint16(len(trials)))
|
||||||
trialData.WriteUint8(trial.Objective)
|
for _, trial := range trials {
|
||||||
trialData.WriteUint32(trial.GoalID)
|
bf.WriteUint32(trial.ID)
|
||||||
trialData.WriteUint16(trial.TimesReq)
|
bf.WriteUint16(trial.Objective)
|
||||||
trialData.WriteUint16(trial.Locale)
|
bf.WriteUint32(trial.GoalID)
|
||||||
trialData.WriteUint16(trial.Reward)
|
bf.WriteUint16(trial.TimesReq)
|
||||||
trialData.WriteUint8(0xFF) // Unk
|
bf.WriteUint16(trial.Locale)
|
||||||
trialData.WriteUint8(0xFF) // MonopolyState
|
bf.WriteUint16(trial.Reward)
|
||||||
trialData.WriteUint16(0) // Unk
|
trial.Monopoly = 0xFFFF // NYI
|
||||||
|
bf.WriteUint16(trial.Monopoly)
|
||||||
|
bf.WriteUint16(trial.Unk)
|
||||||
}
|
}
|
||||||
bf.WriteUint16(count)
|
|
||||||
bf.WriteBytes(trialData.Data())
|
|
||||||
|
|
||||||
// Static bonus rewards
|
// The Winner and Loser Armor IDs are missing
|
||||||
rewards, _ := hex.DecodeString("001901000007015E05F000000000000100000703E81B6300000000010100000C03E8000000000000000100000D0000000000000000000100000100000000000000000002000007015E05F000000000000200000703E81B6300000000010200000C03E8000000000000000200000D0000000000000000000200000400000000000000000003000007015E05F000000000000300000703E81B6300000000010300000C03E8000000000000000300000D0000000000000000000300000100000000000000000004000007015E05F000000000000400000703E81B6300000000010400000C03E8000000000000000400000D0000000000000000000400000400000000000000000005000007015E05F000000000000500000703E81B6300000000010500000C03E8000000000000000500000D00000000000000000005000001000000000000000000")
|
rewards := []FestaReward{
|
||||||
bf.WriteBytes(rewards)
|
{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(s.server.erupeConfig.GameplayOptions.MaximumFP)
|
||||||
bf.WriteUint32(0xD4C001F4)
|
bf.WriteUint16(500)
|
||||||
|
|
||||||
categoryWinners := uint16(0) // NYI
|
categoryWinners := uint16(0) // NYI
|
||||||
bf.WriteUint16(categoryWinners)
|
bf.WriteUint16(categoryWinners)
|
||||||
@@ -239,8 +286,18 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
ps.Uint8(bf, "", true) // Guild Name
|
ps.Uint8(bf, "", true) // Guild Name
|
||||||
}
|
}
|
||||||
|
|
||||||
d, _ := hex.DecodeString("000000000000000100001388000007D0000003E800000064012C00C8009600640032")
|
// Unknown values
|
||||||
bf.WriteBytes(d)
|
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)
|
ps.Uint16(bf, "", false)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -62,7 +63,6 @@ type Guild struct {
|
|||||||
Recruiting bool `db:"recruiting"`
|
Recruiting bool `db:"recruiting"`
|
||||||
FestivalColour FestivalColour `db:"festival_colour"`
|
FestivalColour FestivalColour `db:"festival_colour"`
|
||||||
Souls uint32 `db:"souls"`
|
Souls uint32 `db:"souls"`
|
||||||
Rank uint16 `db:"rank"`
|
|
||||||
AllianceID uint32 `db:"alliance_id"`
|
AllianceID uint32 `db:"alliance_id"`
|
||||||
Icon *GuildIcon `db:"icon"`
|
Icon *GuildIcon `db:"icon"`
|
||||||
|
|
||||||
@@ -115,6 +115,39 @@ func (gi *GuildIcon) Value() (valuer driver.Value, err error) {
|
|||||||
return json.Marshal(gi)
|
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 = `
|
const guildInfoSelectQuery = `
|
||||||
SELECT
|
SELECT
|
||||||
g.id,
|
g.id,
|
||||||
@@ -137,14 +170,6 @@ SELECT
|
|||||||
recruiting,
|
recruiting,
|
||||||
COALESCE((SELECT team FROM festa_registrations fr WHERE fr.guild_id = g.id), 'none') AS festival_colour,
|
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,
|
(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((
|
COALESCE((
|
||||||
SELECT id FROM guild_alliances ga WHERE
|
SELECT id FROM guild_alliances ga WHERE
|
||||||
ga.parent_id = g.id OR
|
ga.parent_id = g.id OR
|
||||||
@@ -615,13 +640,7 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
pkt := p.(*mhfpacket.MsgMhfOperateGuild)
|
pkt := p.(*mhfpacket.MsgMhfOperateGuild)
|
||||||
|
|
||||||
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
characterGuildInfo, err := GetCharacterGuildData(s, s.charID)
|
characterGuildInfo, err := GetCharacterGuildData(s, s.charID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
@@ -630,22 +649,19 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
switch pkt.Action {
|
switch pkt.Action {
|
||||||
case mhfpacket.OPERATE_GUILD_DISBAND:
|
case mhfpacket.OperateGuildDisband:
|
||||||
|
response := 1
|
||||||
if guild.LeaderCharID != s.charID {
|
if guild.LeaderCharID != s.charID {
|
||||||
s.logger.Warn(fmt.Sprintf("character '%d' is attempting to manage guild '%d' without permission", s.charID, guild.ID))
|
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)
|
err = guild.Disband(s)
|
||||||
response := 0x01
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// All successful acks return 0x01, assuming 0x00 is failure
|
response = 0
|
||||||
response = 0x00
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint32(uint32(response))
|
bf.WriteUint32(uint32(response))
|
||||||
case mhfpacket.OPERATE_GUILD_RESIGN:
|
case mhfpacket.OperateGuildResign:
|
||||||
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
sort.Slice(guildMembers[:], func(i, j int) bool {
|
sort.Slice(guildMembers[:], func(i, j int) bool {
|
||||||
@@ -664,25 +680,22 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
guild.Save(s)
|
guild.Save(s)
|
||||||
}
|
}
|
||||||
case mhfpacket.OPERATE_GUILD_APPLY:
|
case mhfpacket.OperateGuildApply:
|
||||||
err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil)
|
err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
bf.WriteUint32(guild.LeaderCharID)
|
bf.WriteUint32(guild.LeaderCharID)
|
||||||
|
} else {
|
||||||
|
bf.WriteUint32(0)
|
||||||
}
|
}
|
||||||
case mhfpacket.OPERATE_GUILD_LEAVE:
|
case mhfpacket.OperateGuildLeave:
|
||||||
var err error
|
|
||||||
|
|
||||||
if characterGuildInfo.IsApplicant {
|
if characterGuildInfo.IsApplicant {
|
||||||
err = guild.RejectApplication(s, s.charID)
|
err = guild.RejectApplication(s, s.charID)
|
||||||
} else {
|
} else {
|
||||||
err = guild.RemoveCharacter(s, s.charID)
|
err = guild.RemoveCharacter(s, s.charID)
|
||||||
}
|
}
|
||||||
|
response := 1
|
||||||
response := 0x01
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// All successful acks return 0x01, assuming 0x00 is failure
|
response = 0
|
||||||
response = 0x00
|
|
||||||
} else {
|
} else {
|
||||||
mail := Mail{
|
mail := Mail{
|
||||||
RecipientID: s.charID,
|
RecipientID: s.charID,
|
||||||
@@ -692,26 +705,25 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
mail.Send(s, nil)
|
mail.Send(s, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint32(uint32(response))
|
bf.WriteUint32(uint32(response))
|
||||||
case mhfpacket.OPERATE_GUILD_DONATE_RANK:
|
case mhfpacket.OperateGuildDonateRank:
|
||||||
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, false))
|
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)
|
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)
|
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)
|
handleAvoidLeadershipUpdate(s, pkt, true)
|
||||||
case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE:
|
case mhfpacket.OperateGuildSetAvoidLeadershipFalse:
|
||||||
handleAvoidLeadershipUpdate(s, pkt, false)
|
handleAvoidLeadershipUpdate(s, pkt, false)
|
||||||
case mhfpacket.OPERATE_GUILD_UPDATE_COMMENT:
|
case mhfpacket.OperateGuildUpdateComment:
|
||||||
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())
|
guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())
|
||||||
guild.Save(s)
|
guild.Save(s)
|
||||||
case mhfpacket.OPERATE_GUILD_UPDATE_MOTTO:
|
case mhfpacket.OperateGuildUpdateMotto:
|
||||||
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
@@ -720,27 +732,29 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
guild.SubMotto = pkt.Data1.ReadUint8()
|
guild.SubMotto = pkt.Data1.ReadUint8()
|
||||||
guild.MainMotto = pkt.Data1.ReadUint8()
|
guild.MainMotto = pkt.Data1.ReadUint8()
|
||||||
guild.Save(s)
|
guild.Save(s)
|
||||||
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_1:
|
case mhfpacket.OperateGuildRenamePugi1:
|
||||||
handleRenamePugi(s, pkt.Data2, guild, 1)
|
handleRenamePugi(s, pkt.Data2, guild, 1)
|
||||||
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_2:
|
case mhfpacket.OperateGuildRenamePugi2:
|
||||||
handleRenamePugi(s, pkt.Data2, guild, 2)
|
handleRenamePugi(s, pkt.Data2, guild, 2)
|
||||||
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_3:
|
case mhfpacket.OperateGuildRenamePugi3:
|
||||||
handleRenamePugi(s, pkt.Data2, guild, 3)
|
handleRenamePugi(s, pkt.Data2, guild, 3)
|
||||||
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_1:
|
case mhfpacket.OperateGuildChangePugi1:
|
||||||
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 1)
|
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)
|
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)
|
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
|
// 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)
|
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())
|
quantity := uint16(pkt.Data1.ReadUint32())
|
||||||
bf.WriteBytes(handleDonateRP(s, quantity, guild, true))
|
bf.WriteBytes(handleDonateRP(s, quantity, guild, true))
|
||||||
// TODO: Move this value onto rp_yesterday and reset to 0... daily?
|
// 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)
|
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())
|
rp := uint16(pkt.Data1.ReadUint32())
|
||||||
var balance uint32
|
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)
|
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.ID)
|
||||||
bf.WriteUint32(guild.LeaderCharID)
|
bf.WriteUint32(guild.LeaderCharID)
|
||||||
bf.WriteUint16(guild.Rank)
|
bf.WriteUint16(guild.Rank())
|
||||||
bf.WriteUint16(guild.MemberCount)
|
bf.WriteUint16(guild.MemberCount)
|
||||||
|
|
||||||
bf.WriteUint8(guild.MainMotto)
|
bf.WriteUint8(guild.MainMotto)
|
||||||
bf.WriteUint8(guild.SubMotto)
|
bf.WriteUint8(guild.SubMotto)
|
||||||
|
|
||||||
// Unk appears to be static
|
// 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)
|
bf.WriteBool(!guild.Recruiting)
|
||||||
|
|
||||||
@@ -952,28 +971,39 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint8(FestivalColourCodes[guild.FestivalColour])
|
bf.WriteUint8(FestivalColourCodes[guild.FestivalColour])
|
||||||
bf.WriteUint32(guild.RankRP)
|
bf.WriteUint32(guild.RankRP)
|
||||||
bf.WriteBytes(guildLeaderName)
|
bf.WriteBytes(guildLeaderName)
|
||||||
bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00}) // Unk
|
bf.WriteUint32(0) // Unk
|
||||||
bf.WriteBool(false) // isReturnGuild
|
bf.WriteBool(false) // isReturnGuild
|
||||||
bf.WriteBool(false) // earnedSpecialHall
|
bf.WriteBool(false) // earnedSpecialHall
|
||||||
bf.WriteBytes([]byte{0x02, 0x02}) // Unk
|
bf.WriteUint8(2)
|
||||||
bf.WriteUint32(guild.EventRP)
|
bf.WriteUint8(2)
|
||||||
|
bf.WriteUint32(guild.EventRP) // Skipped if last byte is <2?
|
||||||
ps.Uint8(bf, guild.PugiName1, true)
|
ps.Uint8(bf, guild.PugiName1, true)
|
||||||
ps.Uint8(bf, guild.PugiName2, true)
|
ps.Uint8(bf, guild.PugiName2, true)
|
||||||
ps.Uint8(bf, guild.PugiName3, true)
|
ps.Uint8(bf, guild.PugiName3, true)
|
||||||
bf.WriteUint8(guild.PugiOutfit1)
|
bf.WriteUint8(guild.PugiOutfit1)
|
||||||
bf.WriteUint8(guild.PugiOutfit2)
|
bf.WriteUint8(guild.PugiOutfit2)
|
||||||
bf.WriteUint8(guild.PugiOutfit3)
|
bf.WriteUint8(guild.PugiOutfit3)
|
||||||
|
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
|
||||||
bf.WriteUint8(guild.PugiOutfit1)
|
bf.WriteUint8(guild.PugiOutfit1)
|
||||||
bf.WriteUint8(guild.PugiOutfit2)
|
bf.WriteUint8(guild.PugiOutfit2)
|
||||||
bf.WriteUint8(guild.PugiOutfit3)
|
bf.WriteUint8(guild.PugiOutfit3)
|
||||||
|
}
|
||||||
bf.WriteUint32(guild.PugiOutfits)
|
bf.WriteUint32(guild.PugiOutfits)
|
||||||
|
|
||||||
// Unk flags
|
if guild.Rank() >= 3 {
|
||||||
bf.WriteUint8(0x3C) // also seen as 0x32 on JP and 0x64 on TW
|
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{
|
bf.WriteUint32(55000)
|
||||||
0x00, 0x00, 0xD6, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
bf.WriteUint32(0)
|
||||||
})
|
bf.WriteUint16(0) // Changing Room RP
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
|
||||||
if guild.AllianceID > 0 {
|
if guild.AllianceID > 0 {
|
||||||
alliance, err := GetAllianceData(s, guild.AllianceID)
|
alliance, err := GetAllianceData(s, guild.AllianceID)
|
||||||
@@ -983,7 +1013,8 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(alliance.ID)
|
bf.WriteUint32(alliance.ID)
|
||||||
bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
|
bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
|
||||||
bf.WriteUint16(alliance.TotalMembers)
|
bf.WriteUint16(alliance.TotalMembers)
|
||||||
bf.WriteUint16(0) // Unk0
|
bf.WriteUint8(0)
|
||||||
|
bf.WriteUint8(0)
|
||||||
ps.Uint16(bf, alliance.Name, true)
|
ps.Uint16(bf, alliance.Name, true)
|
||||||
if alliance.SubGuild1ID > 0 {
|
if alliance.SubGuild1ID > 0 {
|
||||||
if alliance.SubGuild2ID > 0 {
|
if alliance.SubGuild2ID > 0 {
|
||||||
@@ -1001,7 +1032,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
} else {
|
} else {
|
||||||
bf.WriteUint16(0)
|
bf.WriteUint16(0)
|
||||||
}
|
}
|
||||||
bf.WriteUint16(alliance.ParentGuild.Rank)
|
bf.WriteUint16(alliance.ParentGuild.Rank())
|
||||||
bf.WriteUint16(alliance.ParentGuild.MemberCount)
|
bf.WriteUint16(alliance.ParentGuild.MemberCount)
|
||||||
ps.Uint16(bf, alliance.ParentGuild.Name, true)
|
ps.Uint16(bf, alliance.ParentGuild.Name, true)
|
||||||
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
|
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
|
||||||
@@ -1013,7 +1044,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
} else {
|
} else {
|
||||||
bf.WriteUint16(0)
|
bf.WriteUint16(0)
|
||||||
}
|
}
|
||||||
bf.WriteUint16(alliance.SubGuild1.Rank)
|
bf.WriteUint16(alliance.SubGuild1.Rank())
|
||||||
bf.WriteUint16(alliance.SubGuild1.MemberCount)
|
bf.WriteUint16(alliance.SubGuild1.MemberCount)
|
||||||
ps.Uint16(bf, alliance.SubGuild1.Name, true)
|
ps.Uint16(bf, alliance.SubGuild1.Name, true)
|
||||||
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
|
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
|
||||||
@@ -1026,7 +1057,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
} else {
|
} else {
|
||||||
bf.WriteUint16(0)
|
bf.WriteUint16(0)
|
||||||
}
|
}
|
||||||
bf.WriteUint16(alliance.SubGuild2.Rank)
|
bf.WriteUint16(alliance.SubGuild2.Rank())
|
||||||
bf.WriteUint16(alliance.SubGuild2.MemberCount)
|
bf.WriteUint16(alliance.SubGuild2.MemberCount)
|
||||||
ps.Uint16(bf, alliance.SubGuild2.Name, true)
|
ps.Uint16(bf, alliance.SubGuild2.Name, true)
|
||||||
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
|
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
|
||||||
@@ -1043,29 +1074,46 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint16(uint16(len(applicants)))
|
bf.WriteUint16(uint16(len(applicants)))
|
||||||
for _, applicant := range applicants {
|
for _, applicant := range applicants {
|
||||||
bf.WriteUint32(applicant.CharID)
|
bf.WriteUint32(applicant.CharID)
|
||||||
bf.WriteUint16(0)
|
bf.WriteUint32(0)
|
||||||
bf.WriteUint16(0)
|
|
||||||
bf.WriteUint16(applicant.HRP)
|
bf.WriteUint16(applicant.HRP)
|
||||||
bf.WriteUint16(applicant.GR)
|
bf.WriteUint16(applicant.GR)
|
||||||
ps.Uint8(bf, applicant.Name, true)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
type AllianceInvite struct {
|
||||||
alliance application format
|
GuildID uint32
|
||||||
uint16 numapplicants (above)
|
LeaderID uint32
|
||||||
|
Unk0 uint16
|
||||||
uint32 guild id
|
Unk1 uint16
|
||||||
uint32 guild leader id (for mail)
|
Members uint16
|
||||||
uint32 unk (always null in pcap)
|
GuildName string
|
||||||
uint16 member count
|
LeaderName string
|
||||||
uint16 len guild name
|
}
|
||||||
string nullterm guild name
|
allianceInvites := []AllianceInvite{}
|
||||||
uint16 len guild leader name
|
bf.WriteUint8(uint8(len(allianceInvites)))
|
||||||
string nullterm guild leader name
|
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 {
|
if guild.Icon != nil {
|
||||||
bf.WriteUint8(uint8(len(guild.Icon.Parts)))
|
bf.WriteUint8(uint8(len(guild.Icon.Parts)))
|
||||||
@@ -1083,7 +1131,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint16(p.PosY)
|
bf.WriteUint16(p.PosY)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint8(0x00)
|
bf.WriteUint8(0)
|
||||||
}
|
}
|
||||||
bf.WriteUint8(0) // Unk
|
bf.WriteUint8(0) // Unk
|
||||||
|
|
||||||
@@ -1285,7 +1333,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(guild.LeaderCharID)
|
bf.WriteUint32(guild.LeaderCharID)
|
||||||
bf.WriteUint16(guild.MemberCount)
|
bf.WriteUint16(guild.MemberCount)
|
||||||
bf.WriteUint16(0x0000) // Unk
|
bf.WriteUint16(0x0000) // Unk
|
||||||
bf.WriteUint16(guild.Rank)
|
bf.WriteUint16(guild.Rank())
|
||||||
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
|
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
|
||||||
ps.Uint8(bf, guild.Name, true)
|
ps.Uint8(bf, guild.Name, true)
|
||||||
ps.Uint8(bf, guild.LeaderName, true)
|
ps.Uint8(bf, guild.LeaderName, true)
|
||||||
@@ -1347,7 +1395,7 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
if guild != nil {
|
if guild != nil {
|
||||||
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
|
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
|
||||||
if isApplicant {
|
if isApplicant {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1389,8 +1437,15 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
for _, member := range guildMembers {
|
for _, member := range guildMembers {
|
||||||
bf.WriteUint32(member.CharID)
|
bf.WriteUint32(member.CharID)
|
||||||
bf.WriteUint16(member.HRP)
|
bf.WriteUint16(member.HRP)
|
||||||
|
if s.server.erupeConfig.RealClientMode > _config.G7 {
|
||||||
bf.WriteUint16(member.GR)
|
bf.WriteUint16(member.GR)
|
||||||
|
}
|
||||||
|
if s.server.erupeConfig.RealClientMode < _config.ZZ {
|
||||||
|
// Magnet Spike crash workaround
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
} else {
|
||||||
bf.WriteUint16(member.WeaponID)
|
bf.WriteUint16(member.WeaponID)
|
||||||
|
}
|
||||||
if member.WeaponType == 1 || member.WeaponType == 5 || member.WeaponType == 10 { // If weapon is ranged
|
if member.WeaponType == 1 || member.WeaponType == 5 || member.WeaponType == 10 { // If weapon is ranged
|
||||||
bf.WriteUint8(7)
|
bf.WriteUint8(7)
|
||||||
} else {
|
} else {
|
||||||
@@ -1450,7 +1505,6 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
||||||
|
|
||||||
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
|
|
||||||
if guild == nil && s.prevGuildID != 0 {
|
if guild == nil && s.prevGuildID != 0 {
|
||||||
guild, err = GetGuildInfoByID(s, s.prevGuildID)
|
guild, err = GetGuildInfoByID(s, s.prevGuildID)
|
||||||
s.prevGuildID = 0
|
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 := byteframe.NewByteFrame()
|
||||||
bf.WriteUint16(0x00) // Unk
|
bf.WriteUint32(uint32(guild.MemberCount))
|
||||||
bf.WriteUint16(0x00) // Member count
|
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
|
||||||
|
|
||||||
bf.WriteUint16(0x00) // Unk
|
|
||||||
bf.WriteUint16(guild.MemberCount)
|
|
||||||
|
|
||||||
members, _ := GetGuildMembers(s, guild.ID, false)
|
members, _ := GetGuildMembers(s, guild.ID, false)
|
||||||
|
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
bf.WriteUint32(member.CharID)
|
bf.WriteUint32(member.CharID)
|
||||||
bf.WriteBool(member.Recruiter)
|
bf.WriteBool(member.Recruiter)
|
||||||
bf.WriteBytes(make([]byte, 3))
|
bf.WriteBytes(make([]byte, 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -209,14 +209,14 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
bf.WriteUint32(alliance.ParentGuildID)
|
bf.WriteUint32(alliance.ParentGuildID)
|
||||||
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
|
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
|
||||||
bf.WriteUint16(alliance.ParentGuild.Rank)
|
bf.WriteUint16(alliance.ParentGuild.Rank())
|
||||||
bf.WriteUint16(alliance.ParentGuild.MemberCount)
|
bf.WriteUint16(alliance.ParentGuild.MemberCount)
|
||||||
ps.Uint16(bf, alliance.ParentGuild.Name, true)
|
ps.Uint16(bf, alliance.ParentGuild.Name, true)
|
||||||
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
|
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
|
||||||
if alliance.SubGuild1ID > 0 {
|
if alliance.SubGuild1ID > 0 {
|
||||||
bf.WriteUint32(alliance.SubGuild1ID)
|
bf.WriteUint32(alliance.SubGuild1ID)
|
||||||
bf.WriteUint32(alliance.SubGuild1.LeaderCharID)
|
bf.WriteUint32(alliance.SubGuild1.LeaderCharID)
|
||||||
bf.WriteUint16(alliance.SubGuild1.Rank)
|
bf.WriteUint16(alliance.SubGuild1.Rank())
|
||||||
bf.WriteUint16(alliance.SubGuild1.MemberCount)
|
bf.WriteUint16(alliance.SubGuild1.MemberCount)
|
||||||
ps.Uint16(bf, alliance.SubGuild1.Name, true)
|
ps.Uint16(bf, alliance.SubGuild1.Name, true)
|
||||||
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
|
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
|
||||||
@@ -224,7 +224,7 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
if alliance.SubGuild2ID > 0 {
|
if alliance.SubGuild2ID > 0 {
|
||||||
bf.WriteUint32(alliance.SubGuild2ID)
|
bf.WriteUint32(alliance.SubGuild2ID)
|
||||||
bf.WriteUint32(alliance.SubGuild2.LeaderCharID)
|
bf.WriteUint32(alliance.SubGuild2.LeaderCharID)
|
||||||
bf.WriteUint16(alliance.SubGuild2.Rank)
|
bf.WriteUint16(alliance.SubGuild2.Rank())
|
||||||
bf.WriteUint16(alliance.SubGuild2.MemberCount)
|
bf.WriteUint16(alliance.SubGuild2.MemberCount)
|
||||||
ps.Uint16(bf, alliance.SubGuild2.Name, true)
|
ps.Uint16(bf, alliance.SubGuild2.Name, true)
|
||||||
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
|
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.uber.org/zap"
|
"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))
|
s.logger.Error("Failed to load decomyset", zap.Error(err))
|
||||||
}
|
}
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
|
if s.server.erupeConfig.RealClientMode <= _config.G7 {
|
||||||
|
data = []byte{0x00, 0x00}
|
||||||
|
}
|
||||||
data = []byte{0x01, 0x00}
|
data = []byte{0x01, 0x00}
|
||||||
}
|
}
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package channelserver
|
|||||||
import (
|
import (
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"erupe-ce/server/channelserver/compression/deltacomp"
|
"erupe-ce/server/channelserver/compression/deltacomp"
|
||||||
"erupe-ce/server/channelserver/compression/nullcomp"
|
"erupe-ce/server/channelserver/compression/nullcomp"
|
||||||
@@ -56,11 +57,15 @@ func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi)
|
pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi)
|
||||||
|
naviLength := 552
|
||||||
|
if s.server.erupeConfig.RealClientMode <= _config.G7 {
|
||||||
|
naviLength = 280
|
||||||
|
}
|
||||||
var data []byte
|
var data []byte
|
||||||
err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data)
|
err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
s.logger.Error("Failed to load hunternavi", zap.Error(err))
|
s.logger.Error("Failed to load hunternavi", zap.Error(err))
|
||||||
data = make([]byte, 0x226)
|
data = make([]byte, naviLength)
|
||||||
}
|
}
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||||
}
|
}
|
||||||
@@ -68,6 +73,10 @@ func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi)
|
pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi)
|
||||||
if pkt.IsDataDiff {
|
if pkt.IsDataDiff {
|
||||||
|
naviLength := 552
|
||||||
|
if s.server.erupeConfig.RealClientMode <= _config.G7 {
|
||||||
|
naviLength = 280
|
||||||
|
}
|
||||||
var data []byte
|
var data []byte
|
||||||
// Load existing save
|
// Load existing save
|
||||||
err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data)
|
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.
|
// 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.
|
// This is requried as the client will try to send a diff after character creation without a prior MsgMhfSaveHunterNavi packet.
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
data = make([]byte, 0x226)
|
data = make([]byte, naviLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform diff and compress it to write back to db
|
// 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) {
|
func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfContractMercenary)
|
pkt := p.(*mhfpacket.MsgMhfContractMercenary)
|
||||||
switch pkt.Op {
|
switch pkt.Op {
|
||||||
case 0:
|
case 0: // Form loan
|
||||||
s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, s.charID)
|
s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, pkt.CID)
|
||||||
case 1: // Cancel lend
|
case 1: // Cancel lend
|
||||||
s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.charID)
|
s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.charID)
|
||||||
case 2: // Cancel loan
|
case 2: // Cancel loan
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ func handleMsgSysRotateObject(s *Session, p mhfpacket.MHFPacket) {}
|
|||||||
func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgSysSetObjectBinary(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 {
|
for _, session := range s.server.sessions {
|
||||||
if session.charID == s.charID {
|
if session.charID == s.charID {
|
||||||
s.server.userBinaryPartsLock.Lock()
|
s.server.userBinaryPartsLock.Lock()
|
||||||
@@ -91,6 +92,7 @@ func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.server.BroadcastMHF(msg, s)
|
s.server.BroadcastMHF(msg, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
106
server/channelserver/handlers_seibattle.go
Normal file
106
server/channelserver/handlers_seibattle.go
Normal file
@@ -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())
|
||||||
|
}
|
||||||
@@ -7,54 +7,124 @@ import (
|
|||||||
"time"
|
"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) {
|
func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfInfoTournament)
|
pkt := p.(*mhfpacket.MsgMhfInfoTournament)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
|
tournamentInfo0 := []TournamentInfo0{}
|
||||||
|
tournamentInfo21 := []TournamentInfo21{}
|
||||||
|
tournamentInfo22 := []TournamentInfo22{}
|
||||||
|
|
||||||
switch pkt.Unk0 {
|
switch pkt.Unk0 {
|
||||||
case 0:
|
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(0)
|
||||||
|
bf.WriteUint32(uint32(len(tournamentInfo0)))
|
||||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * -10).Unix()))
|
for _, tinfo := range tournamentInfo0 {
|
||||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
bf.WriteUint32(tinfo.ID)
|
||||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
bf.WriteUint32(tinfo.MaxPlayers)
|
||||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
bf.WriteUint32(tinfo.CurrentPlayers)
|
||||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
bf.WriteUint16(tinfo.Unk1)
|
||||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
bf.WriteUint16(tinfo.TextColor)
|
||||||
|
bf.WriteUint32(tinfo.Unk2)
|
||||||
bf.WriteBool(true) // Unk
|
bf.WriteUint32(uint32(tinfo.Time1.Unix()))
|
||||||
bf.WriteBool(false) // Cafe-only
|
bf.WriteUint32(uint32(tinfo.Time2.Unix()))
|
||||||
|
bf.WriteUint32(uint32(tinfo.Time3.Unix()))
|
||||||
bf.WriteUint32(0) // Min HR
|
bf.WriteUint32(uint32(tinfo.Time4.Unix()))
|
||||||
bf.WriteUint32(0) // Max HR
|
bf.WriteUint32(uint32(tinfo.Time5.Unix()))
|
||||||
|
bf.WriteUint32(uint32(tinfo.Time6.Unix()))
|
||||||
ps.Uint8(bf, "Test", false)
|
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())
|
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())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,102 +1,477 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/common/stringsupport"
|
||||||
"erupe-ce/network/mhfpacket"
|
"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) {
|
func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetTowerInfo)
|
pkt := p.(*mhfpacket.MsgMhfGetTowerInfo)
|
||||||
var data []byte
|
var data []*byteframe.ByteFrame
|
||||||
var err error
|
type TowerInfo struct {
|
||||||
/*
|
TRP []TowerInfoTRP
|
||||||
type:
|
Skill []TowerInfoSkill
|
||||||
1 == TOWER_RANK_POINT,
|
History []TowerInfoHistory
|
||||||
2 == GET_OWN_TOWER_SKILL
|
Level []TowerInfoLevel
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
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) {
|
func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfPostTowerInfo)
|
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) {
|
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)
|
pkt := p.(*mhfpacket.MsgMhfGetTenrouirai)
|
||||||
var data []byte
|
var data []*byteframe.ByteFrame
|
||||||
var err error
|
|
||||||
if pkt.Unk0 == 1 {
|
tenrouirai := Tenrouirai{
|
||||||
data, err = hex.DecodeString("0A218EAD000000000000000000000001010000000000060010")
|
Progress: []TenrouiraiProgress{{1, 0, 0, 0}},
|
||||||
} else if pkt.Unk2 == 4 {
|
Data: tenrouiraiData,
|
||||||
data, err = hex.DecodeString("0A218EAD0000000000000000000000210101005000000202010102020104001000000202010102020106003200000202010002020104000C003202020101020201030032000002020101020202059C4000000202010002020105C35000320202010102020201003C00000202010102020203003200000201010001020203002800320201010101020204000C00000201010101020206002800000201010001020101003C00320201020101020105C35000000301020101020106003200000301020001020104001000320301020101020105C350000003010201010202030028000003010200010201030032003203010201010202059C4000000301020101010206002800000301020001010201003C00320301020101010206003200000301020101010204000C000003010200010101010050003203010201010101059C40000003010201010101030032000003010200010101040010003203010001010101060032000003010001010102030028000003010001010101010050003203010000010102059C4000000301000001010206002800000301000001010010")
|
Ticket: []TenrouiraiTicket{{0, 0, 0}},
|
||||||
} else {
|
|
||||||
data = []byte{0x00, 0x00, 0x00, 0x00}
|
|
||||||
s.logger.Info("GET_TENROUIRAI request for unknown type")
|
|
||||||
}
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doAckEarthSucceed(s, pkt.AckHandle, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfPostTenrouirai)
|
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) {
|
if pkt.Op == 2 {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetWeeklySeibatuRankingReward)
|
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))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfPresentBox)
|
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) {
|
func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetGemInfo)
|
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))
|
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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type Config struct {
|
|||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
DB *sqlx.DB
|
DB *sqlx.DB
|
||||||
DiscordBot *discordbot.DiscordBot
|
DiscordBot *discordbot.DiscordBot
|
||||||
ErupeConfig *config.Config
|
ErupeConfig *_config.Config
|
||||||
Name string
|
Name string
|
||||||
Enable bool
|
Enable bool
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ type Server struct {
|
|||||||
Port uint16
|
Port uint16
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
erupeConfig *config.Config
|
erupeConfig *_config.Config
|
||||||
acceptConns chan net.Conn
|
acceptConns chan net.Conn
|
||||||
deleteConns chan net.Conn
|
deleteConns chan net.Conn
|
||||||
sessions map[net.Conn]*Session
|
sessions map[net.Conn]*Session
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ type Stage struct {
|
|||||||
|
|
||||||
// Objects
|
// Objects
|
||||||
objects map[uint32]*Object
|
objects map[uint32]*Object
|
||||||
objectIndex uint8
|
objectIndex uint16
|
||||||
|
|
||||||
// Map of session -> charID.
|
// Map of session -> charID.
|
||||||
// These are clients that are CURRENTLY in the stage
|
// These are clients that are CURRENTLY in the stage
|
||||||
@@ -56,7 +56,6 @@ func NewStage(ID string) *Stage {
|
|||||||
clients: make(map[*Session]uint32),
|
clients: make(map[*Session]uint32),
|
||||||
reservedClientSlots: make(map[uint32]bool),
|
reservedClientSlots: make(map[uint32]bool),
|
||||||
objects: make(map[uint32]*Object),
|
objects: make(map[uint32]*Object),
|
||||||
objectIndex: 0,
|
|
||||||
rawBinaryData: make(map[stageBinaryKey][]byte),
|
rawBinaryData: make(map[stageBinaryKey][]byte),
|
||||||
maxPlayers: 4,
|
maxPlayers: 4,
|
||||||
}
|
}
|
||||||
@@ -97,16 +96,10 @@ func (s *Stage) isQuest() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stage) NextObjectID() uint32 {
|
func (s *Stage) NextObjectID() uint32 {
|
||||||
s.objectIndex = s.objectIndex + 1
|
s.objectIndex++
|
||||||
// Objects beyond 127 do not duplicate correctly
|
|
||||||
// Indexes 0 and 127 does not update position correctly
|
|
||||||
if s.objectIndex == 127 {
|
|
||||||
s.objectIndex = 1
|
|
||||||
}
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint8(0)
|
bf.WriteUint16(127)
|
||||||
bf.WriteUint8(s.objectIndex)
|
bf.WriteUint16(s.objectIndex)
|
||||||
bf.WriteUint16(0)
|
bf.Seek(0, 0)
|
||||||
obj := uint32(bf.Data()[3]) | uint32(bf.Data()[2])<<8 | uint32(bf.Data()[1])<<16 | uint32(bf.Data()[0])<<24
|
return bf.ReadUint32()
|
||||||
return obj
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ import (
|
|||||||
|
|
||||||
type DiscordBot struct {
|
type DiscordBot struct {
|
||||||
Session *discordgo.Session
|
Session *discordgo.Session
|
||||||
config *config.Config
|
config *_config.Config
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
MainGuild *discordgo.Guild
|
MainGuild *discordgo.Guild
|
||||||
RealtimeChannel *discordgo.Channel
|
RealtimeChannel *discordgo.Channel
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Config *config.Config
|
Config *_config.Config
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
type Server struct {
|
type Server struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
erupeConfig *config.Config
|
erupeConfig *_config.Config
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
isShuttingDown bool
|
isShuttingDown bool
|
||||||
@@ -28,7 +28,7 @@ type Server struct {
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
DB *sqlx.DB
|
DB *sqlx.DB
|
||||||
ErupeConfig *config.Config
|
ErupeConfig *_config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates a new Server type.
|
// NewServer creates a new Server type.
|
||||||
@@ -68,7 +68,7 @@ func (s *Server) Shutdown() {
|
|||||||
s.listener.Close()
|
s.listener.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
//acceptClients handles accepting new clients in a loop.
|
// acceptClients handles accepting new clients in a loop.
|
||||||
func (s *Server) acceptClients() {
|
func (s *Server) acceptClients() {
|
||||||
for {
|
for {
|
||||||
conn, err := s.listener.Accept()
|
conn, err := s.listener.Accept()
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ package entranceserver
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"erupe-ce/common/stringsupport"
|
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/config"
|
|
||||||
"erupe-ce/server/channelserver"
|
"erupe-ce/server/channelserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,11 +18,22 @@ var season uint8
|
|||||||
// Server Channels
|
// Server Channels
|
||||||
var currentplayers uint16
|
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
|
serverInfos := config.Entrance.Entries
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
for serverIdx, si := range serverInfos {
|
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
|
sid := (4096 + serverIdx*256) + 16
|
||||||
err := s.db.QueryRow("SELECT season FROM servers WHERE server_id=$1", sid).Scan(&season)
|
err := s.db.QueryRow("SELECT season FROM servers WHERE server_id=$1", sid).Scan(&season)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,12 +52,29 @@ func encodeServerInfo(config *config.Config, s *Server, local bool) []byte {
|
|||||||
bf.WriteUint16(uint16(len(si.Channels)))
|
bf.WriteUint16(uint16(len(si.Channels)))
|
||||||
bf.WriteUint8(si.Type)
|
bf.WriteUint8(si.Type)
|
||||||
bf.WriteUint8(season)
|
bf.WriteUint8(season)
|
||||||
|
if s.erupeConfig.RealClientMode >= _config.G1 {
|
||||||
bf.WriteUint8(si.Recommended)
|
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
|
bf.WriteUint8(0) // Prevents malformed server name
|
||||||
combined := append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...)
|
combined := append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...)
|
||||||
combined = append(combined, stringsupport.UTF8ToSJIS(si.Description)...)
|
combined = append(combined, stringsupport.UTF8ToSJIS(si.Description)...)
|
||||||
bf.WriteBytes(stringsupport.PaddedString(string(combined), 65, false))
|
bf.WriteBytes(stringsupport.PaddedString(string(combined), 65, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.erupeConfig.RealClientMode >= _config.GG {
|
||||||
bf.WriteUint32(si.AllowedClientFlags)
|
bf.WriteUint32(si.AllowedClientFlags)
|
||||||
|
}
|
||||||
|
|
||||||
for channelIdx, ci := range si.Channels {
|
for channelIdx, ci := range si.Channels {
|
||||||
sid = (4096 + serverIdx*256) + (16 + channelIdx)
|
sid = (4096 + serverIdx*256) + (16 + channelIdx)
|
||||||
@@ -91,16 +118,39 @@ func makeHeader(data []byte, respType string, entryCount uint16, key byte) []byt
|
|||||||
return bf.Data()
|
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
|
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)
|
rawServerData := encodeServerInfo(config, s, local)
|
||||||
|
|
||||||
if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.LogOutboundMessages {
|
if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.LogOutboundMessages {
|
||||||
fmt.Printf("[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(rawServerData), hex.Dump(rawServerData))
|
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 := 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()
|
return bf.Data()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,9 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) newUserChara(username string) error {
|
func (s *Server) newUserChara(uid int) error {
|
||||||
var id int
|
|
||||||
err := s.db.QueryRow("SELECT id FROM users WHERE username = $1", username).Scan(&id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var numNewChars int
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -35,7 +29,7 @@ func (s *Server) newUserChara(username string) error {
|
|||||||
user_id, is_female, is_new_character, name, unk_desc_string,
|
user_id, is_female, is_new_character, name, unk_desc_string,
|
||||||
hrp, gr, weapon_type, last_login)
|
hrp, gr, weapon_type, last_login)
|
||||||
VALUES($1, False, True, '', '', 0, 0, 0, $2)`,
|
VALUES($1, False, True, '', '', 0, 0, 0, $2)`,
|
||||||
id,
|
uid,
|
||||||
uint32(time.Now().Unix()),
|
uint32(time.Now().Unix()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -60,19 +54,6 @@ func (s *Server) registerDBAccount(username string, password string) (uint32, er
|
|||||||
return 0, err
|
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
|
return uid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +71,7 @@ type character struct {
|
|||||||
|
|
||||||
func (s *Server) getCharactersForUser(uid uint32) ([]character, error) {
|
func (s *Server) getCharactersForUser(uid uint32) ([]character, error) {
|
||||||
characters := make([]character, 0)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -158,9 +139,6 @@ func (s *Server) getFriendsForCharacters(chars []character) []members {
|
|||||||
}
|
}
|
||||||
friends = append(friends, charFriends...)
|
friends = append(friends, charFriends...)
|
||||||
}
|
}
|
||||||
if len(friends) > 255 { // Uint8
|
|
||||||
friends = friends[:255]
|
|
||||||
}
|
|
||||||
return friends
|
return friends
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,15 +158,12 @@ func (s *Server) getGuildmatesForCharacters(chars []character) []members {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i, _ := range charGuildmates {
|
for i := range charGuildmates {
|
||||||
charGuildmates[i].CID = char.ID
|
charGuildmates[i].CID = char.ID
|
||||||
}
|
}
|
||||||
guildmates = append(guildmates, charGuildmates...)
|
guildmates = append(guildmates, charGuildmates...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(guildmates) > 255 { // Uint8
|
|
||||||
guildmates = guildmates[:255]
|
|
||||||
}
|
|
||||||
return guildmates
|
return guildmates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/server/channelserver"
|
"erupe-ce/server/channelserver"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -13,6 +14,12 @@ import (
|
|||||||
func (s *Session) makeSignResponse(uid uint32) []byte {
|
func (s *Session) makeSignResponse(uid uint32) []byte {
|
||||||
// Get the characters from the DB.
|
// Get the characters from the DB.
|
||||||
chars, err := s.server.getCharactersForUser(uid)
|
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 {
|
if err != nil {
|
||||||
s.logger.Warn("Error getting characters from DB", zap.Error(err))
|
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()
|
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 {
|
if (s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "") || s.client == PS3 {
|
||||||
bf.WriteUint8(2)
|
bf.WriteUint8(2)
|
||||||
} else {
|
} else {
|
||||||
@@ -78,15 +85,23 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
|
|||||||
bf.WriteBool(true) // Use uint16 GR, no reason not to
|
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.Name, 16, true)) // Character name
|
||||||
bf.WriteBytes(stringsupport.PaddedString(char.UnkDescString, 32, false)) // unk str
|
bf.WriteBytes(stringsupport.PaddedString(char.UnkDescString, 32, false)) // unk str
|
||||||
|
if s.server.erupeConfig.RealClientMode >= _config.G7 {
|
||||||
bf.WriteUint16(char.GR)
|
bf.WriteUint16(char.GR)
|
||||||
bf.WriteUint16(0) // Unk
|
bf.WriteUint8(0) // Unk
|
||||||
|
bf.WriteUint8(0) // Unk
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friends := s.server.getFriendsForCharacters(chars)
|
friends := s.server.getFriendsForCharacters(chars)
|
||||||
if len(friends) == 0 {
|
if len(friends) == 0 {
|
||||||
bf.WriteUint8(0)
|
bf.WriteUint8(0)
|
||||||
|
} else {
|
||||||
|
if len(friends) > 255 {
|
||||||
|
bf.WriteUint8(255)
|
||||||
|
bf.WriteUint16(uint16(len(friends)))
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint8(uint8(len(friends)))
|
bf.WriteUint8(uint8(len(friends)))
|
||||||
|
}
|
||||||
for _, friend := range friends {
|
for _, friend := range friends {
|
||||||
bf.WriteUint32(friend.CID)
|
bf.WriteUint32(friend.CID)
|
||||||
bf.WriteUint32(friend.ID)
|
bf.WriteUint32(friend.ID)
|
||||||
@@ -97,8 +112,13 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
|
|||||||
guildmates := s.server.getGuildmatesForCharacters(chars)
|
guildmates := s.server.getGuildmatesForCharacters(chars)
|
||||||
if len(guildmates) == 0 {
|
if len(guildmates) == 0 {
|
||||||
bf.WriteUint8(0)
|
bf.WriteUint8(0)
|
||||||
|
} else {
|
||||||
|
if len(guildmates) > 255 {
|
||||||
|
bf.WriteUint8(255)
|
||||||
|
bf.WriteUint16(uint16(len(guildmates)))
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint8(uint8(len(guildmates)))
|
bf.WriteUint8(uint8(len(guildmates)))
|
||||||
|
}
|
||||||
for _, guildmate := range guildmates {
|
for _, guildmate := range guildmates {
|
||||||
bf.WriteUint32(guildmate.CID)
|
bf.WriteUint32(guildmate.CID)
|
||||||
bf.WriteUint32(guildmate.ID)
|
bf.WriteUint32(guildmate.ID)
|
||||||
@@ -107,12 +127,12 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.server.erupeConfig.HideLoginNotice {
|
if s.server.erupeConfig.HideLoginNotice {
|
||||||
bf.WriteUint8(0)
|
bf.WriteBool(false)
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint8(uint8(len(s.server.erupeConfig.LoginNotices)))
|
bf.WriteBool(true)
|
||||||
for _, notice := range s.server.erupeConfig.LoginNotices {
|
bf.WriteUint8(0)
|
||||||
ps.Uint32(bf, notice, true)
|
bf.WriteUint8(0)
|
||||||
}
|
ps.Uint16(bf, strings.Join(s.server.erupeConfig.LoginNotices[:], "<PAGE>"), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint32(s.server.getLastCID(uid))
|
bf.WriteUint32(s.server.getLastCID(uid))
|
||||||
@@ -132,35 +152,37 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
|
|||||||
bf.WriteUint16(0x4E20)
|
bf.WriteUint16(0x4E20)
|
||||||
ps.Uint16(bf, "", false) // unk ipv4
|
ps.Uint16(bf, "", false) // unk ipv4
|
||||||
bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix()))
|
bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix()))
|
||||||
bf.WriteUint32(0x00000000)
|
bf.WriteUint32(0)
|
||||||
bf.WriteUint32(0x0A5197DF) // unk id
|
|
||||||
|
|
||||||
mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent
|
mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent
|
||||||
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt
|
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt
|
||||||
if mezfes {
|
if mezfes {
|
||||||
|
// We can just use the start timestamp as the event ID
|
||||||
|
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
|
||||||
// Start time
|
// Start time
|
||||||
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
|
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
|
||||||
// End time
|
// End time
|
||||||
bf.WriteUint32(uint32(channelserver.TimeWeekNext().Unix()))
|
bf.WriteUint32(uint32(channelserver.TimeWeekNext().Unix()))
|
||||||
bf.WriteUint8(2) // Unk
|
bf.WriteUint8(2) // Unk
|
||||||
bf.WriteUint32(20) // Single tickets
|
bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MezfesSoloTickets)
|
||||||
bf.WriteUint32(10) // Group tickets
|
bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MezfesGroupTickets)
|
||||||
bf.WriteUint8(8) // Stalls open
|
bf.WriteUint8(8) // Stalls open
|
||||||
bf.WriteUint8(0xA) // Unk
|
bf.WriteUint8(10) // Stall Map
|
||||||
bf.WriteUint8(0x3) // Pachinko
|
bf.WriteUint8(3) // Pachinko
|
||||||
bf.WriteUint8(0x6) // Nyanrendo
|
bf.WriteUint8(6) // Nyanrendo
|
||||||
bf.WriteUint8(0x9) // Point stall
|
bf.WriteUint8(9) // Point stall
|
||||||
if alt {
|
if alt {
|
||||||
bf.WriteUint8(0x2) // Tokotoko
|
bf.WriteUint8(2) // Tokotoko Partnya
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint8(0x4) // Volpakkun
|
bf.WriteUint8(4) // Volpakkun Together
|
||||||
}
|
}
|
||||||
bf.WriteUint8(0x8) // Battle cats
|
bf.WriteUint8(8) // Dokkan Battle Cats
|
||||||
bf.WriteUint8(0x5) // Gook
|
bf.WriteUint8(5) // Goocoo Scoop
|
||||||
bf.WriteUint8(0x7) // Honey
|
bf.WriteUint8(7) // Honey Panic
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
|
bf.WriteUint32(0)
|
||||||
}
|
}
|
||||||
return bf.Data()
|
return bf.Data()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (s *Session) handlePacket(pkt []byte) error {
|
|||||||
case "VITASGN:100":
|
case "VITASGN:100":
|
||||||
s.client = VITA
|
s.client = VITA
|
||||||
s.handlePSSGN(bf)
|
s.handlePSSGN(bf)
|
||||||
case "WIIUSGN:100":
|
case "WIIUSGN:100", "WIIUSGN:000":
|
||||||
s.client = WIIU
|
s.client = WIIU
|
||||||
s.handleWIIUSGN(bf)
|
s.handleWIIUSGN(bf)
|
||||||
case "VITACOGLNK:100":
|
case "VITACOGLNK:100":
|
||||||
@@ -124,6 +124,13 @@ func (s *Session) handleWIIUSGN(bf *byteframe.ByteFrame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) handlePSSGN(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.ReadNullTerminatedBytes() // VITA = 0000000256, PS3 = 0000000255
|
||||||
_ = bf.ReadBytes(2) // VITA = 1, PS3 = !
|
_ = bf.ReadBytes(2) // VITA = 1, PS3 = !
|
||||||
_ = bf.ReadBytes(82)
|
_ = bf.ReadBytes(82)
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
DB *sqlx.DB
|
DB *sqlx.DB
|
||||||
ErupeConfig *config.Config
|
ErupeConfig *_config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server is a MHF sign server.
|
// Server is a MHF sign server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
erupeConfig *config.Config
|
erupeConfig *_config.Config
|
||||||
sessions map[int]*Session
|
sessions map[int]*Session
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
DB *sqlx.DB
|
DB *sqlx.DB
|
||||||
ErupeConfig *config.Config
|
ErupeConfig *_config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server is the MHF custom launcher sign server.
|
// Server is the MHF custom launcher sign server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
erupeConfig *config.Config
|
erupeConfig *_config.Config
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
isShuttingDown bool
|
isShuttingDown bool
|
||||||
|
|||||||
Reference in New Issue
Block a user