This commit is contained in:
xl3lackout
2022-02-25 19:44:26 -05:00
commit a92897404a
690 changed files with 70775 additions and 0 deletions

13
Erupe/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
www/jp/
.idea/
vendor/
bin/*.bin
bin/quests/*.bin
bin/questlists/*.bin
bin/scenarios/*.bin
bin/debug/*.bin
savedata/
Erupe.exe
*.lnk
*.bat

1
Erupe/Event List.txt Normal file
View File

@@ -0,0 +1 @@
0 is no event, 1 is "Week 1 Timestamp (broken), 2 is "Week 2 Timestamp (broken), 3 is Diva Defense

BIN
Erupe/Gifts/Cadeaux.bin Normal file

Binary file not shown.

BIN
Erupe/Gifts/Description.bin Normal file

Binary file not shown.

21
Erupe/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2019 The Erupe Developers from Einherjar Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

83
Erupe/README.md Normal file
View File

@@ -0,0 +1,83 @@
# Erupe
## WARNING
This project is in its infancy and has no reliable active developer, no documentation, and no support.
# General info
Currently allows a JP MHF client (with GameGuard removed) to:
* Login and register an account (registration is automatic if account doesn't exist)
* Create a character
* Get ingame to the main city
* See other players walk around
* Do quests
* Use chat*
# Installation
## Server
1. Clone the repo with `git clone https://github.com/Andoryuuta/Erupe.git`
2. Install PostgreSQL
3. Launch psql shell, `CREATE DATABASE erupe;`.
4. Setup database with golang-migrate:
Windows:
```
> go get -tags 'postgres' -u github.com/golang-migrate/migrate/v4/cmd/migrate/
> set POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable
> cd erupe
> migrate -database %POSTGRESQL_URL% -path migrations up
```
Linux:
```
> go get -tags 'postgres' -u github.com/golang-migrate/migrate/v4/cmd/migrate/
> export POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable
> cd erupe
> migrate -database $POSTGRESQL_URL -path migrations up
```
(Replacing `postgres:password` with your postgres username and password)
5. Edit the config.json
Namely:
* Update the database username and password
* Update the `host_ip` and `ip` fields (there are multiple) to your external IP if you are hosting for multiple clients.
6. Place quest/scenario binaries.
The quest and scenario binary files should be placed in `bin/quests/` and `bin/scenarios` respectively.
## Launcher
Erupe ships with a rudimentary custom launcher, so you don't need to obtain the original TW/JP files to simply get ingame. However, it does still support using the original files if you choose to. To set this up, place a copy of the original launcher html/js/css in `./www/tw/`, and `/www/jp/` for the TW and JP files respectively.
Then, modify the the `/launcher/js/launcher.js` file as such:
* Find the call to `startUpdateProcess();` in a case statement and replace it with `finishUpdateProcess();`. (This disables the file check and updating)
* (JP ONLY): replace all uses of "https://" with "http://" in the file.
Finally, edit the config.json and set `UseOriginalLauncherFiles` to `true` under the launcher settings.
# Usage
### Note: If you are switching to/from the custom launcher html, you will have to clear your IE cache @ `C:\Users\<user>\AppData\Local\Microsoft\Windows\INetCache`.
## Server
```
cd Erupe
go run .
```
## Client
Add to hosts:
```
127.0.0.1 mhfg.capcom.com.tw
127.0.0.1 mhf-n.capcom.com.tw
127.0.0.1 cog-members.mhf-z.jp
127.0.0.1 www.capcom-onlinegames.jp
127.0.0.1 srv-mhf.capcom-networks.jp
```
Run mhf.exe normally (with locale emulator or appropriate timezone).

View File

@@ -0,0 +1,16 @@
BEGIN;
CREATE TABLE questlists (
ind int NOT NULL PRIMARY KEY,
questlist bytea
);
END;
INSERT INTO questlists (ind, questlist) VALUES ('0', pg_read_binary_file('c:\save\quest_0_0.bin'));
INSERT INTO questlists (ind, questlist) VALUES ('42', pg_read_binary_file('c:\save\quest_42_2A.bin'));
INSERT INTO questlists (ind, questlist) VALUES ('84', pg_read_binary_file('c:\save\quest_84_54.bin'));
INSERT INTO questlists (ind, questlist) VALUES ('126', pg_read_binary_file('c:\save\quest_126_7E.bin'));
INSERT INTO questlists (ind, questlist) VALUES ('168', pg_read_binary_file('c:\save\quest_168_A8.bin'));

View File

@@ -0,0 +1,8 @@
package bfutil
import "bytes"
// UpToNull returns the given byte slice's data, up to (not including) the first null byte.
func UpToNull(data []byte) []byte {
return bytes.SplitN(data, []byte{0x00}, 2)[0]
}

View File

@@ -0,0 +1,40 @@
package stringstack
import (
"errors"
"sync"
)
// StringStack is a basic LIFO "stack" for storing strings.
type StringStack struct {
sync.Mutex
stack []string
}
// New creates a new instance of StringStack
func New() *StringStack {
return &StringStack{}
}
// Push pushes a string onto the stack.
func (s *StringStack) Push(v string) {
s.Lock()
defer s.Unlock()
s.stack = append(s.stack, v)
}
// Pop pops a string from the stack.
func (s *StringStack) Pop() (string, error) {
s.Lock()
defer s.Unlock()
if len(s.stack) == 0 {
return "", errors.New("no items on stack")
}
x := s.stack[len(s.stack)-1]
s.stack = s.stack[:len(s.stack)-1]
return x, nil
}

View File

@@ -0,0 +1,93 @@
package stringsupport
import (
"bytes"
"io/ioutil"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
)
// StringConverter is a small helper for encoding/decoding strings.
type StringConverter struct {
Encoding encoding.Encoding
}
// Decode decodes the given bytes as the set encoding.
func (sc *StringConverter) Decode(data []byte) (string, error) {
decoded, err := ioutil.ReadAll(transform.NewReader(bytes.NewBuffer(data), sc.Encoding.NewDecoder()))
if err != nil {
return "", err
}
return string(decoded), nil
}
// MustDecode decodes the given bytes as the set encoding. Panics on decode failure.
func (sc *StringConverter) MustDecode(data []byte) string {
decoded, err := sc.Decode(data)
if err != nil {
panic(err)
}
return decoded
}
// Encode encodes the given string as the set encoding.
func (sc *StringConverter) Encode(data string) ([]byte, error) {
encoded, err := ioutil.ReadAll(transform.NewReader(bytes.NewBuffer([]byte(data)), sc.Encoding.NewEncoder()))
if err != nil {
return nil, err
}
return encoded, nil
}
// MustEncode encodes the given string as the set encoding. Panics on encode failure.
func (sc *StringConverter) MustEncode(data string) []byte {
encoded, err := sc.Encode(data)
if err != nil {
panic(err)
}
return encoded
}
/*
func MustConvertShiftJISToUTF8(text string) string {
result, err := ConvertShiftJISToUTF8(text)
if err != nil {
panic(err)
}
return result
}
func MustConvertUTF8ToShiftJIS(text string) string {
result, err := ConvertUTF8ToShiftJIS(text)
if err != nil {
panic(err)
}
return result
}
func ConvertShiftJISToUTF8(text string) (string, error) {
r := bytes.NewBuffer([]byte(text))
decoded, err := ioutil.ReadAll(transform.NewReader(r, japanese.ShiftJIS.NewDecoder()))
if err != nil {
return "", err
}
return string(decoded), nil
}
*/
// ConvertUTF8ToShiftJIS converts a UTF8 string to a Shift-JIS []byte.
func ConvertUTF8ToShiftJIS(text string) ([]byte, error) {
r := bytes.NewBuffer([]byte(text))
encoded, err := ioutil.ReadAll(transform.NewReader(r, japanese.ShiftJIS.NewEncoder()))
if err != nil {
return nil, err
}
return encoded, nil
}

153
Erupe/config.json Normal file
View File

@@ -0,0 +1,153 @@
{
"host_ip": "",
"bin_path": "bin",
"devmode": true,
"devmodeoptions": {
"serverName" : "",
"cleandb": false,
"maxlauncherhr": true,
"LogOutboundMessages": false,
"Event": 0,
"OpcodeMessages": false,
"SaveDumps": {
"Enabled": true,
"OutputDir": "savedata"
}
},
"discord": {
"enabled": false,
"bottoken": "",
"channelid": ""
},
"database": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "",
"database": "erupe"
},
"launcher": {
"port": 80,
"UseOriginalLauncherFiles": false
},
"sign": {
"port": 53312
},
"channel": {
"port1": 54001,
"port2": 54002,
"port3": 54003,
"port4": 54004
},
"entrance": {
"port": 53310,
"entries": [
{
"name": " Server #1",
"ip": "",
"unk2": 0,
"type": 3,
"season": 3,
"unk6": 0,
"allowedclientflags": "4096",
"channels": [
{
"port": 54001,
"MaxPlayers": 100,
"CurrentPlayers": 0,
"Unk4": 0,
"Unk5": 0,
"Unk6": 0,
"Unk7": 0,
"Unk8": 0,
"Unk9": 0,
"Unk10": 319,
"Unk11": 248,
"Unk12": 159,
"Unk13": 12345
}
]
},
{
"name": " Server #2",
"ip": "",
"unk2": 0,
"type": 1,
"season": 3,
"unk6": 0,
"allowedclientflags": 0,
"channels": [
{
"port": 54002,
"MaxPlayers": 50,
"CurrentPlayers": 0,
"Unk4": 0,
"Unk5": 0,
"Unk6": 0,
"Unk7": 0,
"Unk8": 0,
"Unk9": 0,
"Unk10": 318,
"Unk11": 251,
"Unk12": 155,
"Unk13": 12345
}
]
},
{
"name": " Server #3",
"ip": "",
"unk2": 0,
"type": 2,
"season": 1,
"unk6": 0,
"allowedclientflags": 0,
"channels": [
{
"port": 54003,
"MaxPlayers": 50,
"CurrentPlayers": 0,
"Unk4": 0,
"Unk5": 0,
"Unk6": 0,
"Unk7": 0,
"Unk8": 0,
"Unk9": 0,
"Unk10": 318,
"Unk11": 251,
"Unk12": 155,
"Unk13": 12345
}
]
},
{
"name": " Server #4",
"ip": "",
"unk2": 0,
"type": 4,
"season": 0,
"unk6": 0,
"allowedclientflags": 0,
"channels": [
{
"port": 54004,
"MaxPlayers": 50,
"CurrentPlayers": 0,
"Unk4": 0,
"Unk5": 0,
"Unk6": 0,
"Unk7": 0,
"Unk8": 0,
"Unk9": 0,
"Unk10": 318,
"Unk11": 251,
"Unk12": 155,
"Unk13": 12345
}
]
}
]
}
}

157
Erupe/config/config.go Normal file
View File

@@ -0,0 +1,157 @@
package config
import (
"log"
"net"
"github.com/spf13/viper"
)
// Config holds the global server-wide config.
type Config struct {
HostIP string `mapstructure:"host_ip"`
BinPath string `mapstructure:"bin_path"`
DevMode bool
DevModeOptions DevModeOptions
Discord Discord
Database Database
Launcher Launcher
Sign Sign
Channel Channel
Entrance Entrance
}
// DevModeOptions holds various debug/temporary options for use while developing Erupe.
type DevModeOptions struct {
ServerName string // To get specific instance server about (Current Players/Event Week)
CleanDB bool // Automatically wipes the DB on server reset.
MaxLauncherHR bool // Sets the HR returned in the launcher to HR9 so that you can join non-beginner worlds.
FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages
LogOutboundMessages bool // Log all messages sent to the clients
Event int // Changes the current event
OpcodeMessages bool // Get all message for Opcodes
SaveDumps SaveDumpOptions
}
type SaveDumpOptions struct {
Enabled bool
OutputDir string
}
// Discord holds the discord integration config.
type Discord struct {
Enabled bool
BotToken string
ChannelID string
}
// Database holds the postgres database config.
type Database struct {
Host string
Port int
User string
Password string
Database string
}
// Launcher holds the launcher server config.
type Launcher struct {
Port int
UseOriginalLauncherFiles bool
}
// Sign holds the sign server config.
type Sign struct {
Port int
}
// Channel holds the channel server config.
type Channel struct {
Port1 int
Port2 int
Port3 int
Port4 int
}
// Entrance holds the entrance server config.
type Entrance struct {
Port uint16
Entries []EntranceServerInfo
}
// EntranceServerInfo represents an entry in the serverlist.
type EntranceServerInfo struct {
IP string
Unk2 uint16
Type uint8 // Server type. 0=?, 1=open, 2=cities, 3=newbie, 4=bar
Season uint8 // Server activity. 0 = green, 1 = orange, 2 = blue
Unk6 uint8 // Something to do with server recommendation on 0, 3, and 5.
Name string // Server name, 66 byte null terminated Shift-JIS(JP) or Big5(TW).
// 4096(PC, PS3/PS4)?, 8258(PC, PS3/PS4)?, 8192 == nothing?
// THIS ONLY EXISTS IF Binary8Header.type == "SV2", NOT "SVR"!
AllowedClientFlags uint32
Channels []EntranceChannelInfo
}
// EntranceChannelInfo represents an entry in a server's channel list.
type EntranceChannelInfo struct {
Port uint16
MaxPlayers uint16
CurrentPlayers uint16
Unk4 uint16
Unk5 uint16
Unk6 uint16
Unk7 uint16
Unk8 uint16
Unk9 uint16
Unk10 uint16
Unk11 uint16
Unk12 uint16
Unk13 uint16
}
// getOutboundIP4 gets the preferred outbound ip4 of this machine
// From https://stackoverflow.com/a/37382208
func getOutboundIP4() net.IP {
conn, err := net.Dial("udp4", "8.8.8.8:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.To4()
}
// LoadConfig loads the given config toml file.
func LoadConfig() (*Config, error) {
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.SetDefault("DevModeOptions.SaveDumps", SaveDumpOptions{
Enabled: false,
OutputDir: "savedata",
})
err := viper.ReadInConfig()
if err != nil {
return nil, err
}
c := &Config{}
err = viper.Unmarshal(c)
if err != nil {
return nil, err
}
if c.HostIP == "" {
c.HostIP = getOutboundIP4().To4().String()
}
return c, nil
}

75
Erupe/go.mod Normal file
View File

@@ -0,0 +1,75 @@
module github.com/Solenataris/Erupe
go 1.16
require (
cloud.google.com/go v0.98.0 // indirect
cloud.google.com/go/spanner v1.27.0 // indirect
cloud.google.com/go/storage v1.18.2 // indirect
github.com/Andoryuuta/byteframe v0.0.0-20200114030334-8979c5cc4c4a
github.com/Azure/go-autorest/autorest/adal v0.9.17 // indirect
github.com/ClickHouse/clickhouse-go v1.5.1 // indirect
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect
github.com/aws/aws-sdk-go v1.42.19 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.7.4 // indirect
github.com/bwmarrin/discordgo v0.23.2
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
github.com/cockroachdb/cockroach-go/v2 v2.2.4 // indirect
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/denisenkom/go-mssqldb v0.11.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/gocql/gocql v0.0.0-20211015133455-b225f9b53fa1 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-migrate/migrate/v4 v4.15.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/go-github/v35 v35.3.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/jackc/pgx/v4 v4.14.1 // indirect
github.com/jmoiron/sqlx v1.3.4
github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/ktrysmt/go-bitbucket v0.9.32 // indirect
github.com/lib/pq v1.10.4
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mutecomm/go-sqlcipher/v4 v4.4.2 // indirect
github.com/nakagami/firebirdsql v0.9.3 // indirect
github.com/neo4j/neo4j-go-driver v1.8.3 // indirect
github.com/pierrec/lz4/v4 v4.1.12 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96
github.com/shopspring/decimal v1.3.1 // indirect
github.com/snowflakedb/gosnowflake v1.6.4 // indirect
github.com/spf13/viper v1.8.1
github.com/xanzy/go-gitlab v0.52.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.mongodb.org/mongo-driver v1.8.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.18.1
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
golang.org/x/net v0.0.0-20211205041911-012df41ee64c // indirect
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/text v0.3.7
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/tools v0.1.8 // indirect
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0 // indirect
google.golang.org/grpc v1.42.0 // indirect
modernc.org/ccgo/v3 v3.12.86 // indirect
modernc.org/ql v1.4.0 // indirect
modernc.org/sqlite v1.14.2 // indirect
)

1972
Erupe/go.sum Normal file

File diff suppressed because it is too large Load Diff

177
Erupe/main.go Normal file
View File

@@ -0,0 +1,177 @@
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/Solenataris/Erupe/config"
"github.com/Solenataris/Erupe/server/channelserver"
"github.com/Solenataris/Erupe/server/entranceserver"
"github.com/Solenataris/Erupe/server/launcherserver"
"github.com/Solenataris/Erupe/server/signserver"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
// Temporary DB auto clean on startup for quick development & testing.
func cleanDB(db *sqlx.DB) {
_ = db.MustExec("DELETE FROM guild_characters")
_ = db.MustExec("DELETE FROM guilds")
_ = db.MustExec("DELETE FROM characters")
_ = db.MustExec("DELETE FROM sign_sessions")
_ = db.MustExec("DELETE FROM users")
}
func main() {
zapLogger, _ := zap.NewDevelopment()
defer zapLogger.Sync()
logger := zapLogger.Named("main")
logger.Info("Starting Erupe")
// Load the configuration.
erupeConfig, err := config.LoadConfig()
if err != nil {
logger.Fatal("Failed to load config", zap.Error(err))
}
// Create the postgres DB pool.
connectString := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname= %s sslmode=disable",
erupeConfig.Database.Host,
erupeConfig.Database.Port,
erupeConfig.Database.User,
erupeConfig.Database.Password,
erupeConfig.Database.Database,
)
db, err := sqlx.Open("postgres", connectString)
if err != nil {
logger.Fatal("Failed to open sql database", zap.Error(err))
}
// Test the DB connection.
err = db.Ping()
if err != nil {
logger.Fatal("Failed to ping database", zap.Error(err))
}
logger.Info("Connected to database")
// Clean the DB if the option is on.
if erupeConfig.DevMode && erupeConfig.DevModeOptions.CleanDB {
logger.Info("Cleaning DB")
cleanDB(db)
logger.Info("Done cleaning DB")
}
// Now start our server(s).
// Launcher HTTP server.
launcherServer := launcherserver.NewServer(
&launcherserver.Config{
Logger: logger.Named("launcher"),
ErupeConfig: erupeConfig,
DB: db,
UseOriginalLauncherFiles: erupeConfig.Launcher.UseOriginalLauncherFiles,
})
err = launcherServer.Start()
if err != nil {
logger.Fatal("Failed to start launcher server", zap.Error(err))
}
logger.Info("Started launcher server.")
// Entrance server.
entranceServer := entranceserver.NewServer(
&entranceserver.Config{
Logger: logger.Named("entrance"),
ErupeConfig: erupeConfig,
DB: db,
})
err = entranceServer.Start()
if err != nil {
logger.Fatal("Failed to start entrance server", zap.Error(err))
}
logger.Info("Started entrance server.")
// Sign server.
signServer := signserver.NewServer(
&signserver.Config{
Logger: logger.Named("sign"),
ErupeConfig: erupeConfig,
DB: db,
})
err = signServer.Start()
if err != nil {
logger.Fatal("Failed to start sign server", zap.Error(err))
}
logger.Info("Started sign server.")
// Channel Server
channelServer1 := channelserver.NewServer(
&channelserver.Config{
Logger: logger.Named("channel"),
ErupeConfig: erupeConfig,
DB: db,
})
err = channelServer1.Start(erupeConfig.Channel.Port1)
if err != nil {
logger.Fatal("Failed to start channel server1", zap.Error(err))
}
logger.Info("Started channel server.")
// Channel Server
channelServer2 := channelserver.NewServer(
&channelserver.Config{
Logger: logger.Named("channel"),
ErupeConfig: erupeConfig,
DB: db,
})
err = channelServer2.Start(erupeConfig.Channel.Port2)
if err != nil {
logger.Fatal("Failed to start channel server2", zap.Error(err))
}
// Channel Server
channelServer3 := channelserver.NewServer(
&channelserver.Config{
Logger: logger.Named("channel"),
ErupeConfig: erupeConfig,
DB: db,
})
err = channelServer3.Start(erupeConfig.Channel.Port3)
if err != nil {
logger.Fatal("Failed to start channel server3", zap.Error(err))
}
// Channel Server
channelServer4 := channelserver.NewServer(
&channelserver.Config{
Logger: logger.Named("channel"),
ErupeConfig: erupeConfig,
DB: db,
})
err = channelServer4.Start(erupeConfig.Channel.Port4)
if err != nil {
logger.Fatal("Failed to start channel server4", zap.Error(err))
}
// Wait for exit or interrupt with ctrl+C.
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
logger.Info("Trying to shutdown gracefully.")
channelServer4.Shutdown()
channelServer3.Shutdown()
channelServer2.Shutdown()
channelServer1.Shutdown()
signServer.Shutdown()
entranceServer.Shutdown()
launcherServer.Shutdown()
time.Sleep(1 * time.Second)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,60 @@
package binpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// ChatType represents the chat message type (Thanks to @Alice on discord for identifying these!)
type ChatType uint8
// Chat types
const (
ChatTypeLocal ChatType = 1
ChatTypeGuild = 2
ChatTypeAlliance = 3
ChatTypeParty = 4
ChatTypeWhisper = 5
)
// MsgBinChat is a binpacket for chat messages.
type MsgBinChat struct {
Unk0 uint8
Type ChatType
Flags uint16
Message string
SenderName string
}
// Opcode returns the ID associated with this packet type.
func (m *MsgBinChat) Opcode() network.PacketID {
return network.MSG_SYS_CAST_BINARY
}
// Parse parses the packet from binary
func (m *MsgBinChat) Parse(bf *byteframe.ByteFrame) error {
m.Unk0 = bf.ReadUint8()
m.Type = ChatType(bf.ReadUint8())
m.Flags = bf.ReadUint16()
senderNameSize := bf.ReadUint16()
messageSize := bf.ReadUint16()
// TODO(Andoryuuta): Need proper shift-jis and null termination.
m.Message = string(bf.ReadBytes(uint(messageSize))[:messageSize-1])
m.SenderName = string(bf.ReadBytes(uint(senderNameSize))[:senderNameSize-1])
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgBinChat) Build(bf *byteframe.ByteFrame) error {
bf.WriteUint8(m.Unk0)
bf.WriteUint8(uint8(m.Type))
bf.WriteUint16(m.Flags)
bf.WriteUint16(uint16(len(m.SenderName) + 1))
bf.WriteUint16(uint16(len(m.Message) + 1))
bf.WriteNullTerminatedBytes([]byte(m.Message))
bf.WriteNullTerminatedBytes([]byte(m.SenderName))
return nil
}

View File

@@ -0,0 +1,29 @@
package binpacket
import (
"github.com/Solenataris/Erupe/common/stringsupport"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
type MsgBinMailNotify struct {
SenderName string
}
func (m MsgBinMailNotify) Parse(bf *byteframe.ByteFrame) error {
panic("implement me")
}
func (m MsgBinMailNotify) Build(bf *byteframe.ByteFrame) error {
bf.WriteUint8(0x01) // Unk
byteName, _ := stringsupport.ConvertUTF8ToShiftJIS(m.SenderName)
bf.WriteBytes(byteName)
bf.WriteBytes(make([]byte, 21-len(byteName)))
return nil
}
func (m MsgBinMailNotify) Opcode() network.PacketID {
return network.MSG_SYS_CASTED_BINARY
}

View File

@@ -0,0 +1,46 @@
package binpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgBinTargeted is a format used for some broadcast types
// to target specific players, instead of groups (world, stage, etc).
// It forwards a normal binpacket in it's RawDataPayload
type MsgBinTargeted struct {
TargetCount uint16
TargetCharIDs []uint32
RawDataPayload []byte // The regular binary payload to be forwarded to the targets.
}
// Opcode returns the ID associated with this packet type.
func (m *MsgBinTargeted) Opcode() network.PacketID {
return network.MSG_SYS_CAST_BINARY
}
// Parse parses the packet from binary
func (m *MsgBinTargeted) Parse(bf *byteframe.ByteFrame) error {
m.TargetCount = bf.ReadUint16()
m.TargetCharIDs = make([]uint32, m.TargetCount)
for i := uint16(0); i < m.TargetCount; i++ {
m.TargetCharIDs[i] = bf.ReadUint32()
}
m.RawDataPayload = bf.DataFromCurrent()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgBinTargeted) Build(bf *byteframe.ByteFrame) error {
bf.WriteUint16(m.TargetCount)
for i := 0; i < int(m.TargetCount); i++ {
bf.WriteUint32(m.TargetCharIDs[i])
}
bf.WriteBytes(m.RawDataPayload)
return nil
}

View File

@@ -0,0 +1,8 @@
package clientctx
import "github.com/Solenataris/Erupe/common/stringsupport"
// ClientContext holds contextual data required for packet encoding/decoding.
type ClientContext struct {
StrConv *stringsupport.StringConverter
}

125
Erupe/network/crypt_conn.go Normal file
View File

@@ -0,0 +1,125 @@
package network
import (
"encoding/hex"
"errors"
"fmt"
"io"
"net"
"github.com/Solenataris/Erupe/network/crypto"
)
// CryptConn represents a MHF encrypted two-way connection,
// it automatically handles encryption, decryption, and key rotation via it's methods.
type CryptConn struct {
conn net.Conn
readKeyRot uint32
sendKeyRot uint32
sentPackets int32
prevRecvPacketCombinedCheck uint16
prevSendPacketCombinedCheck uint16
}
// NewCryptConn creates a new CryptConn with proper default values.
func NewCryptConn(conn net.Conn) *CryptConn {
cc := &CryptConn{
conn: conn,
readKeyRot: 995117,
sendKeyRot: 995117,
}
return cc
}
// ReadPacket reads an packet from the connection and returns the decrypted data.
func (cc *CryptConn) ReadPacket() ([]byte, error) {
// Read the raw 14 byte header.
headerData := make([]byte, CryptPacketHeaderLength)
_, err := io.ReadFull(cc.conn, headerData)
if err != nil {
return nil, err
}
// Parse the data into a usable struct.
cph, err := NewCryptPacketHeader(headerData)
if err != nil {
return nil, err
}
// Now read the encrypted packet body after getting its size from the header.
encryptedPacketBody := make([]byte, cph.DataSize)
_, err = io.ReadFull(cc.conn, encryptedPacketBody)
if err != nil {
return nil, err
}
// Update the key rotation before decrypting.
if cph.KeyRotDelta != 0 {
cc.readKeyRot = (uint32(cph.KeyRotDelta) * (cc.readKeyRot + 1))
}
out, combinedCheck, check0, check1, check2 := crypto.Decrypt(encryptedPacketBody, cc.readKeyRot, nil)
if cph.Check0 != check0 || cph.Check1 != check1 || cph.Check2 != check2 {
fmt.Printf("got c0 %X, c1 %X, c2 %X\n", check0, check1, check2)
fmt.Printf("want c0 %X, c1 %X, c2 %X\n", cph.Check0, cph.Check1, cph.Check2)
fmt.Printf("headerData:\n%s\n", hex.Dump(headerData))
fmt.Printf("encryptedPacketBody:\n%s\n", hex.Dump(encryptedPacketBody))
// Attempt to bruteforce it.
fmt.Println("Crypto out of sync? Attempting bruteforce")
for key := byte(0); key < 255; key++ {
out, combinedCheck, check0, check1, check2 = crypto.Decrypt(encryptedPacketBody, 0, &key)
//fmt.Printf("Key: 0x%X\n%s\n", key, hex.Dump(out))
if cph.Check0 == check0 && cph.Check1 == check1 && cph.Check2 == check2 {
fmt.Printf("Bruceforce successful, override key: 0x%X\n", key)
// Try to fix key for subsequent packets?
//cc.readKeyRot = (uint32(key) << 1) + 999983
cc.prevRecvPacketCombinedCheck = combinedCheck
return out, nil
}
}
return nil, errors.New("decrypted data checksum doesn't match header")
}
cc.prevRecvPacketCombinedCheck = combinedCheck
return out, nil
}
// SendPacket encrypts and sends a packet.
func (cc *CryptConn) SendPacket(data []byte) error {
keyRotDelta := byte(3)
if keyRotDelta != 0 {
cc.sendKeyRot = (uint32(keyRotDelta) * (cc.sendKeyRot + 1))
}
// Encrypt the data
encData, combinedCheck, check0, check1, check2 := crypto.Encrypt(data, cc.sendKeyRot, nil)
header := &CryptPacketHeader{}
header.Pf0 = byte(((uint(len(encData)) >> 12) & 0xF3) | 3)
header.KeyRotDelta = keyRotDelta
header.PacketNum = uint16(cc.sentPackets)
header.DataSize = uint16(len(encData))
header.PrevPacketCombinedCheck = cc.prevSendPacketCombinedCheck
header.Check0 = check0
header.Check1 = check1
header.Check2 = check2
headerBytes, err := header.Encode()
if err != nil {
return err
}
cc.conn.Write(headerBytes)
cc.conn.Write(encData)
cc.sentPackets++
cc.prevSendPacketCombinedCheck = combinedCheck
return nil
}

View File

@@ -0,0 +1,90 @@
package network
import (
"bytes"
"encoding/binary"
)
const (
// CryptPacketHeaderLength represents the byte-length of
// an encrypted packet header.
CryptPacketHeaderLength = 14
)
// CryptPacketHeader represents the parsed information of an encrypted packet header.
type CryptPacketHeader struct {
Pf0 byte
KeyRotDelta byte
PacketNum uint16
DataSize uint16
PrevPacketCombinedCheck uint16
Check0 uint16
Check1 uint16
Check2 uint16
}
// NewCryptPacketHeader parses raw bytes into a CryptPacketHeader
func NewCryptPacketHeader(data []byte) (*CryptPacketHeader, error) {
var c = CryptPacketHeader{}
r := bytes.NewReader(data)
var err error
err = binary.Read(r, binary.BigEndian, &c.Pf0)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.KeyRotDelta)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.PacketNum)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.DataSize)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.PrevPacketCombinedCheck)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.Check0)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.Check1)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &c.Check2)
if err != nil {
return nil, err
}
return &c, nil
}
// Encode encodes the CryptPacketHeader into raw bytes.
func (c *CryptPacketHeader) Encode() ([]byte, error) {
buf := bytes.NewBuffer([]byte{})
var data = []interface{}{
c.Pf0,
c.KeyRotDelta,
c.PacketNum,
c.DataSize,
c.PrevPacketCombinedCheck,
c.Check0,
c.Check1,
c.Check2,
}
for _, v := range data {
err := binary.Write(buf, binary.BigEndian, v)
if err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}

View File

@@ -0,0 +1,84 @@
package crypto
var (
_encryptKey = []byte{0x90, 0x51, 0x26, 0x25, 0x04, 0xBF, 0xCF, 0x4C, 0x92, 0x02, 0x52, 0x7A, 0x70, 0x1A, 0x41, 0x88, 0x8C, 0xC2, 0xCE, 0xB8, 0xF6, 0x57, 0x7E, 0xBA, 0x83, 0x63, 0x2C, 0x24, 0x9A, 0x67, 0x86, 0x0C, 0xBE, 0x72, 0xFD, 0xB6, 0x7B, 0x79, 0xB0, 0x22, 0x5A, 0x60, 0x5C, 0x4F, 0x49, 0xE2, 0x0E, 0xF5, 0x3A, 0x81, 0xAE, 0x11, 0x6B, 0xF0, 0xA1, 0x01, 0xE8, 0x65, 0x8D, 0x5B, 0xDC, 0xCC, 0x93, 0x18, 0xB3, 0xAB, 0x77, 0xF7, 0x8E, 0xEC, 0xEF, 0x05, 0x00, 0xCA, 0x4E, 0xA7, 0xBC, 0xB5, 0x10, 0xC6, 0x6C, 0xC0, 0xC4, 0xE5, 0x87, 0x3F, 0xC1, 0x82, 0x29, 0x96, 0x45, 0x73, 0x07, 0xCB, 0x43, 0xF9, 0xF3, 0x08, 0x89, 0xD0, 0x99, 0x6A, 0x3B, 0x37, 0x19, 0xD4, 0x40, 0xEA, 0xD7, 0x85, 0x16, 0x66, 0x1E, 0x9C, 0x39, 0xBB, 0xEE, 0x4A, 0x03, 0x8A, 0x36, 0x2D, 0x13, 0x1D, 0x56, 0x48, 0xC7, 0x0D, 0x59, 0xB2, 0x44, 0xA3, 0xFE, 0x8B, 0x32, 0x1B, 0x84, 0xA0, 0x2E, 0x62, 0x17, 0x42, 0xB9, 0x9B, 0x2B, 0x75, 0xD8, 0x1C, 0x3C, 0x4D, 0x76, 0x27, 0x6E, 0x28, 0xD3, 0x33, 0xC3, 0x21, 0xAF, 0x34, 0x23, 0xDD, 0x68, 0x9F, 0xF1, 0xAD, 0xE1, 0xB4, 0xE7, 0xA6, 0x74, 0x15, 0x4B, 0xFA, 0x3D, 0x5F, 0x7C, 0xDA, 0x2F, 0x0A, 0xE3, 0x7D, 0xC8, 0xB7, 0x12, 0x6F, 0x9E, 0xA9, 0x14, 0x53, 0x97, 0x8F, 0x64, 0xF4, 0xF8, 0xA2, 0xA4, 0x2A, 0xD2, 0x47, 0x9D, 0x71, 0xC5, 0xE9, 0x06, 0x98, 0x20, 0x54, 0x80, 0xAA, 0xF2, 0xAC, 0x50, 0xD6, 0x7F, 0xD9, 0xC9, 0xCD, 0x69, 0x46, 0x6D, 0x30, 0xB1, 0x58, 0x0B, 0x55, 0xD1, 0x5D, 0xD5, 0xBD, 0x31, 0xDE, 0xA5, 0xE4, 0x91, 0x0F, 0x61, 0x38, 0xDF, 0xA8, 0xE6, 0x3E, 0x1F, 0x35, 0xED, 0xDB, 0x94, 0xEB, 0x09, 0x5E, 0x95, 0xFB, 0xFC, 0xE0, 0x78, 0xFF}
_decryptKey = []byte{0x48, 0x37, 0x09, 0x76, 0x04, 0x47, 0xCC, 0x5C, 0x61, 0xF8, 0xB3, 0xE0, 0x1F, 0x7F, 0x2E, 0xEB, 0x4E, 0x33, 0xB8, 0x7A, 0xBC, 0xAB, 0x6E, 0x8C, 0x3F, 0x68, 0x0D, 0x87, 0x93, 0x7B, 0x70, 0xF2, 0xCE, 0x9D, 0x27, 0xA0, 0x1B, 0x03, 0x02, 0x97, 0x99, 0x58, 0xC5, 0x90, 0x1A, 0x79, 0x8A, 0xB2, 0xDD, 0xE6, 0x86, 0x9B, 0x9F, 0xF3, 0x78, 0x67, 0xED, 0x72, 0x30, 0x66, 0x94, 0xAE, 0xF1, 0x55, 0x6A, 0x0E, 0x8D, 0x5E, 0x82, 0x5A, 0xDB, 0xC7, 0x7D, 0x2C, 0x75, 0xAC, 0x07, 0x95, 0x4A, 0x2B, 0xD4, 0x01, 0x0A, 0xBD, 0xCF, 0xE1, 0x7C, 0x15, 0xDF, 0x80, 0x28, 0x3B, 0x2A, 0xE3, 0xF9, 0xAF, 0x29, 0xEC, 0x8B, 0x19, 0xC0, 0x39, 0x6F, 0x1D, 0xA2, 0xDA, 0x65, 0x34, 0x50, 0xDC, 0x98, 0xB9, 0x0C, 0xC9, 0x21, 0x5B, 0xAA, 0x91, 0x96, 0x42, 0xFE, 0x25, 0x0B, 0x24, 0xB0, 0xB5, 0x16, 0xD6, 0xD0, 0x31, 0x57, 0x18, 0x88, 0x6D, 0x1E, 0x54, 0x0F, 0x62, 0x77, 0x85, 0x10, 0x3A, 0x44, 0xBF, 0x00, 0xEA, 0x08, 0x3E, 0xF6, 0xFA, 0x59, 0xBE, 0xCD, 0x64, 0x1C, 0x8F, 0x71, 0xC8, 0xBA, 0xA3, 0x89, 0x36, 0xC3, 0x83, 0xC4, 0xE8, 0xA9, 0x4B, 0xEF, 0xBB, 0xD1, 0x41, 0xD3, 0xA5, 0x32, 0x9E, 0x26, 0xDE, 0x81, 0x40, 0xA7, 0x4D, 0x23, 0xB7, 0x13, 0x8E, 0x17, 0x73, 0x4C, 0xE5, 0x20, 0x05, 0x51, 0x56, 0x11, 0x9C, 0x52, 0xCA, 0x4F, 0x7E, 0xB6, 0xD8, 0x49, 0x5D, 0x3D, 0xD9, 0x12, 0x06, 0x63, 0xE2, 0xC6, 0x9A, 0x69, 0xE4, 0xD5, 0x6C, 0x92, 0xD7, 0xB1, 0xF5, 0x3C, 0xA1, 0xE7, 0xEE, 0xFD, 0xA6, 0x2D, 0xB4, 0xE9, 0x53, 0xF0, 0xA8, 0x38, 0xCB, 0x6B, 0xF7, 0x45, 0xF4, 0x74, 0x46, 0x35, 0xA4, 0xD2, 0x60, 0xC1, 0x2F, 0x14, 0x43, 0xC2, 0x5F, 0xAD, 0xFB, 0xFC, 0x22, 0x84, 0xFF}
_sharedCryptKey = []byte{0xDD, 0xA8, 0x5F, 0x1E, 0x57, 0xAF, 0xC0, 0xCC, 0x43, 0x35, 0x8F, 0xBB, 0x6F, 0xE6, 0xA1, 0xD6, 0x60, 0xB9, 0x1A, 0xAE, 0x20, 0x49, 0x24, 0x81, 0x21, 0xFE, 0x86, 0x2B, 0x98, 0xB7, 0xB3, 0xD2, 0x91, 0x01, 0x3A, 0x4C, 0x65, 0x92, 0x1C, 0xF4, 0xBE, 0xDD, 0xD9, 0x08, 0xE6, 0x81, 0x98, 0x1B, 0x8D, 0x60, 0xF3, 0x6F, 0xA1, 0x47, 0x24, 0xF1, 0x53, 0x45, 0xC8, 0x7B, 0x88, 0x80, 0x4E, 0x36, 0xC3, 0x0D, 0xC9, 0xD6, 0x8B, 0x08, 0x19, 0x0B, 0xA5, 0xC1, 0x11, 0x4C, 0x60, 0xF8, 0x5D, 0xFC, 0x15, 0x68, 0x7E, 0x32, 0xC0, 0x50, 0xAB, 0x64, 0x1F, 0x8A, 0xD4, 0x08, 0x39, 0x7F, 0xC2, 0xFB, 0xBA, 0x6C, 0xF0, 0xE6, 0xB0, 0x31, 0x10, 0xC1, 0xBF, 0x75, 0x43, 0xBB, 0x18, 0x04, 0x0D, 0xD1, 0x97, 0xF7, 0x23, 0x21, 0x83, 0x8B, 0xCA, 0x25, 0x2B, 0xA3, 0x03, 0x13, 0xEA, 0xAE, 0xFE, 0xF0, 0xEB, 0xFD, 0x85, 0x57, 0x53, 0x65, 0x41, 0x2A, 0x40, 0x99, 0xC0, 0x94, 0x65, 0x7E, 0x7C, 0x93, 0x82, 0xB0, 0xB3, 0xE5, 0xC0, 0x21, 0x09, 0x84, 0xD5, 0xEF, 0x9F, 0xD1, 0x7E, 0xDC, 0x4D, 0xF5, 0x7E, 0xCD, 0x45, 0x3C, 0x7F, 0xF5, 0x59, 0x98, 0xC6, 0x55, 0xFC, 0x9F, 0xA3, 0xB7, 0x74, 0xEE, 0x31, 0x98, 0xE6, 0xB7, 0xBE, 0x26, 0xF4, 0x3C, 0x76, 0xF1, 0x23, 0x7E, 0x02, 0x4E, 0x3C, 0xD1, 0xC7, 0x28, 0x23, 0x73, 0xC4, 0xD9, 0x5E, 0x0D, 0xA1, 0x80, 0xA5, 0xAA, 0x26, 0x0A, 0xA3, 0x44, 0x82, 0x74, 0xE6, 0x3C, 0x44, 0x27, 0x51, 0x0D, 0x5F, 0xC7, 0x9C, 0xD6, 0x63, 0x67, 0xA5, 0x27, 0x97, 0x38, 0xFB, 0x2D, 0xD3, 0xD6, 0x60, 0x25, 0x83, 0x4D, 0x37, 0x5B, 0x40, 0x59, 0x11, 0x77, 0x51, 0x11, 0x14, 0x18, 0x07, 0x63, 0xB1, 0x34, 0x3D, 0xB8, 0x60, 0x13, 0xC2, 0xE8, 0x13, 0x82}
)
// Encrypt encrypts the given data using MHF's custom encryption+checksum method.
// if a overrideByteKey value is supplied (!= nil), it will be used to override the derived/truncated key byte.
func Encrypt(data []byte, key uint32, overrideByteKey *byte) (outputData []byte, combinedCheck uint16, check0 uint16, check1 uint16, check2 uint16) {
return _generalCrypt(data, key, 0, overrideByteKey)
}
// Decrypt decrypts the given data using MHF's custom decryption+checksum method.
// if a overrideByteKey value is supplied (!= nil), it will be used to override the derived/truncated key byte.
func Decrypt(data []byte, key uint32, overrideByteKey *byte) (outputData []byte, combinedCheck uint16, check0 uint16, check1 uint16, check2 uint16) {
return _generalCrypt(data, key, 1, overrideByteKey)
}
// _generalCrypt is a generalized MHF crypto function that can perform both encryption and decryption,
// these two crypto operations are combined into a single function because they shared most of their logic.
// encrypt: cryptType==0
// decrypt: cryptType==1
func _generalCrypt(data []byte, rotKey uint32, cryptType int, overrideByteKey *byte) ([]byte, uint16, uint16, uint16, uint16) {
cryptKeyTruncByte := byte(((rotKey >> 1) % 999983) & 0xFF)
if overrideByteKey != nil {
cryptKeyTruncByte = *overrideByteKey
}
derivedCryptKey := int32((uint32(len(data)) * (uint32(cryptKeyTruncByte) + 1)) & 0xFFFFFFFF)
sharedBufIdx := byte(1)
accumulator0 := uint32(0)
accumulator1 := uint32(0)
accumulator2 := uint32(0)
var outputData []byte
if cryptType == 0 {
for i := 0; i < len(data); i++ {
// Do the encryption for this iteration
encKeyIdx := int32(((uint32(derivedCryptKey) >> 10) ^ uint32(data[i])) & 0xFF)
derivedCryptKey = (0x4FD * (derivedCryptKey + 1))
encKeyByte := _encryptKey[encKeyIdx]
// Update the checksum accumulators.
accumulator2 = uint32((accumulator2 + (uint32(sharedBufIdx) * uint32(data[i]))) & 0xFFFFFFFF)
accumulator1 = uint32((accumulator1 + uint32(encKeyIdx)) & 0xFFFFFFFF)
accumulator0 = uint32((accumulator0 + (uint32(encKeyByte)<<(i&7))&0xFFFFFFFF) & 0xFFFFFFFF)
// Append the output.
outputData = append(outputData, _sharedCryptKey[sharedBufIdx]^encKeyByte)
// Update the sharedBufIdx for the next iteration.
sharedBufIdx = data[i]
}
} else if cryptType == 1 {
for i := 0; i < len(data); i++ {
// Do the decryption for this iteration
oldSharedBufIdx := sharedBufIdx
tIdx := data[i] ^ _sharedCryptKey[sharedBufIdx]
decKeyByte := _decryptKey[tIdx]
sharedBufIdx = byte(((uint32(derivedCryptKey) >> 10) ^ uint32(decKeyByte)) & 0xFF)
// Update the checksum accumulators.
accumulator0 = (accumulator0 + ((uint32(tIdx) << (i & 7)) & 0xFFFFFFFF))
accumulator1 = (accumulator1 + uint32(decKeyByte)) & 0xFFFFFFFF
accumulator2 = (accumulator2 + ((uint32(oldSharedBufIdx) * uint32(sharedBufIdx)) & 0xFFFFFFFF)) & 0xFFFFFFFF
// Append the output.
outputData = append(outputData, sharedBufIdx)
// Update the key pos for next iteration.
derivedCryptKey = (0x4FD * (derivedCryptKey + 1))
}
}
combinedCheck := uint16((accumulator1 + (accumulator0 >> 1) + (accumulator2 >> 2)) & 0xFFFF)
check0 := uint16((accumulator0 ^ ((accumulator0 & 0xFFFF0000) >> 16)) & 0xFFFF)
check1 := uint16((accumulator1 ^ ((accumulator1 & 0xFFFF0000) >> 16)) & 0xFFFF)
check2 := uint16((accumulator2 ^ ((accumulator2 & 0xFFFF0000) >> 16)) & 0xFFFF)
return outputData, combinedCheck, check0, check1, check2
}

View File

@@ -0,0 +1,104 @@
package crypto
import (
"bytes"
"encoding/hex"
"fmt"
"testing"
)
var commonTestData = []byte{0x74, 0x65, 0x73, 0x74}
var tests = []struct {
decryptedData []byte
key uint32
encryptedData []byte
ecc, ec0, ec1, ec2 uint16
}{
{
commonTestData,
0,
[]byte{0x46, 0x53, 0x28, 0x5E},
0x2976, 0x06ea, 0x0215, 0x08FB3,
},
{
commonTestData,
3,
[]byte{0x46, 0x95, 0x88, 0xEA},
0x2AE4, 0x0A56, 0x01CD, 0x08FB3,
},
/*
// TODO(Andoryuuta): This case fails. Debug the client and figure out if this is valid expected data.
{
commonTestData,
995117,
[]byte{0x46, 0x28, 0xFF, 0xAA},
0x2A22, 0x09D4, 0x014C, 0x08FB3,
},
*/
{
commonTestData,
0x7FFFFFFF,
[]byte{0x46, 0x53, 0x28, 0x5E},
0x2976, 0x06ea, 0x0215, 0x08FB3,
},
{
commonTestData,
0x80000000,
[]byte{0x46, 0x95, 0x88, 0xEA},
0x2AE4, 0x0A56, 0x01CD, 0x08FB3,
},
{
commonTestData,
0xFFFFFFFF,
[]byte{0x46, 0xB5, 0xDC, 0xB2},
0x2ADD, 0x09A6, 0x021E, 0x08FB3,
},
{
[]byte{0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x12, 0x00, 0xDE, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x18, 0x46, 0x00, 0x00, 0x80, 0x3F, 0xDC, 0xE4, 0x0A, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x67, 0xD3, 0x5B, 0x00, 0x77, 0x01, 0x78, 0x00, 0x77, 0x01, 0x4F, 0x01, 0x5B, 0x6F, 0x76, 0xC5, 0x30, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDD, 0x17, 0x46, 0x00, 0x00, 0x80, 0x3F, 0x9E, 0x11, 0x0C, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x37, 0x64, 0x00, 0x2C, 0x01, 0x64, 0x00, 0x2C, 0x01, 0x4F, 0x01, 0x5B, 0x6F, 0x76, 0xC5, 0x00, 0x10},
2000476,
[]byte{0x2E, 0x52, 0x24, 0xE3, 0x05, 0x2B, 0xFC, 0x04, 0x0B, 0x26, 0x90, 0xEA, 0x61, 0xDB, 0x8D, 0x27, 0xCB, 0xB1, 0x69, 0xA1, 0x77, 0x80, 0x4A, 0xC2, 0xA0, 0xBD, 0x50, 0x54, 0xF5, 0xC2, 0x94, 0x66, 0xBB, 0xCE, 0x53, 0x29, 0xEE, 0xB4, 0xFA, 0xF6, 0x5F, 0x8D, 0x80, 0x3E, 0x5D, 0x5F, 0xB0, 0x53, 0xE6, 0x92, 0x17, 0x80, 0xE7, 0xED, 0xE7, 0xDC, 0x61, 0xF0, 0xCD, 0xE4, 0x41, 0x82, 0x21, 0xBA, 0x47, 0xAB, 0x58, 0xFF, 0x30, 0x76, 0x80, 0x2D, 0x38, 0xF4, 0xDF, 0x86, 0x8C, 0x6C, 0x8D, 0x33, 0x4C, 0x37, 0xA3, 0xDA, 0x01, 0x3C, 0x98, 0x66, 0x1F, 0xB9, 0xE2, 0xEA, 0xF0, 0x84, 0xE8, 0xAA, 0x00, 0x3D, 0x4A, 0xB6, 0xF2, 0x3D, 0x91, 0x58, 0x4B, 0x0B, 0xE2, 0xD5, 0xC7, 0x39, 0x4D, 0x59, 0xED, 0xC3, 0x61, 0x6F, 0x6E, 0x69, 0x9B, 0x3C},
0xCFF8, 0x086B, 0x3BAE, 0x4057,
},
}
func TestEncrypt(t *testing.T) {
for k, tt := range tests {
testname := fmt.Sprintf("encrypt_test_%d", k)
t.Run(testname, func(t *testing.T) {
out, cc, c0, c1, c2 := Encrypt(tt.decryptedData, tt.key, nil)
if cc != tt.ecc {
t.Errorf("got cc 0x%X, want 0x%X", cc, tt.ecc)
} else if c0 != tt.ec0 {
t.Errorf("got c0 0x%X, want 0x%X", c0, tt.ec0)
} else if c1 != tt.ec1 {
t.Errorf("got c1 0x%X, want 0x%X", c1, tt.ec1)
} else if c2 != tt.ec2 {
t.Errorf("got c2 0x%X, want 0x%X", c2, tt.ec2)
} else if !bytes.Equal(out, tt.encryptedData) {
t.Errorf("got out\n\t%s\nwant\n\t%s", hex.Dump(out), hex.Dump(tt.encryptedData))
}
})
}
}
func TestDecrypt(t *testing.T) {
for k, tt := range tests {
testname := fmt.Sprintf("decrypt_test_%d", k)
t.Run(testname, func(t *testing.T) {
out, cc, c0, c1, c2 := Decrypt(tt.encryptedData, tt.key, nil)
if cc != tt.ecc {
t.Errorf("got cc 0x%X, want 0x%X", cc, tt.ecc)
} else if c0 != tt.ec0 {
t.Errorf("got c0 0x%X, want 0x%X", c0, tt.ec0)
} else if c1 != tt.ec1 {
t.Errorf("got c1 0x%X, want 0x%X", c1, tt.ec1)
} else if c2 != tt.ec2 {
t.Errorf("got c2 0x%X, want 0x%X", c2, tt.ec2)
} else if !bytes.Equal(out, tt.decryptedData) {
t.Errorf("got out\n\t%s\nwant\n\t%s", hex.Dump(out), hex.Dump(tt.decryptedData))
}
})
}
}

View File

@@ -0,0 +1,29 @@
package mhfpacket
import (
"github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
)
// Parser is the interface that wraps the Parse method.
type Parser interface {
Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error
}
// Builder is the interface that wraps the Build method.
type Builder interface {
Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error
}
// Opcoder is the interface that wraps the Opcode method.
type Opcoder interface {
Opcode() network.PacketID
}
// MHFPacket is the interface that groups the Parse, Build, and Opcode methods.
type MHFPacket interface {
Parser
Builder
Opcoder
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
)
// MsgCaExchangeItem represents the MSG_CA_EXCHANGE_ITEM
type MsgCaExchangeItem struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgCaExchangeItem) Opcode() network.PacketID {
return network.MSG_CA_EXCHANGE_ITEM
}
// Parse parses the packet from binary
func (m *MsgCaExchangeItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgCaExchangeItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,28 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgHead represents the MSG_HEAD
type MsgHead struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgHead) Opcode() network.PacketID {
return network.MSG_HEAD
}
// Parse parses the packet from binary
func (m *MsgHead) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgHead) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,28 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcceptReadReward represents the MSG_MHF_ACCEPT_READ_REWARD
type MsgMhfAcceptReadReward struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcceptReadReward) Opcode() network.PacketID {
return network.MSG_MHF_ACCEPT_READ_REWARD
}
// Parse parses the packet from binary
func (m *MsgMhfAcceptReadReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcceptReadReward) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,41 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireCafeItem represents the MSG_MHF_ACQUIRE_CAFE_ITEM
type MsgMhfAcquireCafeItem struct {
AckHandle uint32
// Valid sizes, not sure if [un]signed.
ItemType uint16
ItemID uint16
Quant uint16
PointCost uint32
Unk0 uint16
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireCafeItem) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_CAFE_ITEM
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireCafeItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.ItemType = bf.ReadUint16()
m.ItemID = bf.ReadUint16()
m.Quant = bf.ReadUint16()
m.PointCost = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireCafeItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,35 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireDistItem represents the MSG_MHF_ACQUIRE_DIST_ITEM
type MsgMhfAcquireDistItem struct {
AckHandle uint32
// Valid field size(s), not sure about the types.
Unk0 uint8
Unk1 uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireDistItem) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_DIST_ITEM
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
m.Unk1 = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireDistItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,35 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireExchangeShop represents the MSG_MHF_ACQUIRE_EXCHANGE_SHOP
type MsgMhfAcquireExchangeShop struct {
AckHandle uint32
DataSize uint16
RawDataPayload []byte
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireExchangeShop) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_EXCHANGE_SHOP
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireExchangeShop) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.DataSize = bf.ReadUint16()
m.RawDataPayload = bf.ReadBytes(uint(m.DataSize))
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireExchangeShop) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle)
bf.WriteUint16(m.DataSize)
bf.WriteBytes(m.RawDataPayload)
return nil
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireFesta represents the MSG_MHF_ACQUIRE_FESTA
type MsgMhfAcquireFesta struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireFesta) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_FESTA
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireFesta) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireFesta) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireFestaIntermediatePrize represents the MSG_MHF_ACQUIRE_FESTA_INTERMEDIATE_PRIZE
type MsgMhfAcquireFestaIntermediatePrize struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireFestaIntermediatePrize) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_FESTA_INTERMEDIATE_PRIZE
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireFestaIntermediatePrize) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireFestaIntermediatePrize) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireFestaPersonalPrize represents the MSG_MHF_ACQUIRE_FESTA_PERSONAL_PRIZE
type MsgMhfAcquireFestaPersonalPrize struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireFestaPersonalPrize) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_FESTA_PERSONAL_PRIZE
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireFestaPersonalPrize) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireFestaPersonalPrize) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireGuildAdventure represents the MSG_MHF_ACQUIRE_GUILD_ADVENTURE
type MsgMhfAcquireGuildAdventure struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireGuildAdventure) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_GUILD_ADVENTURE
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireGuildAdventure) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireGuildAdventure) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireGuildTresure represents the MSG_MHF_ACQUIRE_GUILD_TRESURE
type MsgMhfAcquireGuildTresure struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireGuildTresure) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_GUILD_TRESURE
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireGuildTresure) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireGuildTresure) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,30 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireGuildTresureSouvenir represents the MSG_MHF_ACQUIRE_GUILD_TRESURE_SOUVENIR
type MsgMhfAcquireGuildTresureSouvenir struct {
AckHandle uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireGuildTresureSouvenir) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_GUILD_TRESURE_SOUVENIR
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireGuildTresureSouvenir) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireGuildTresureSouvenir) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireItem represents the MSG_MHF_ACQUIRE_ITEM
type MsgMhfAcquireItem struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireItem) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_ITEM
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireMonthlyItem represents the MSG_MHF_ACQUIRE_MONTHLY_ITEM
type MsgMhfAcquireMonthlyItem struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireMonthlyItem) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_MONTHLY_ITEM
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireMonthlyItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireMonthlyItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,30 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireMonthlyReward represents the MSG_MHF_ACQUIRE_MONTHLY_REWARD
type MsgMhfAcquireMonthlyReward struct {
AckHandle uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireMonthlyReward) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_MONTHLY_REWARD
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireMonthlyReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireMonthlyReward) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireTitle represents the MSG_MHF_ACQUIRE_TITLE
type MsgMhfAcquireTitle struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireTitle) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_TITLE
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireTitle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireTitle) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireTournament represents the MSG_MHF_ACQUIRE_TOURNAMENT
type MsgMhfAcquireTournament struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireTournament) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_TOURNAMENT
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireTournament) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireTournament) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAcquireUdItem represents the MSG_MHF_ACQUIRE_UD_ITEM
type MsgMhfAcquireUdItem struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAcquireUdItem) Opcode() network.PacketID {
return network.MSG_MHF_ACQUIRE_UD_ITEM
}
// Parse parses the packet from binary
func (m *MsgMhfAcquireUdItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAcquireUdItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,36 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddAchievement represents the MSG_MHF_ADD_ACHIEVEMENT
type MsgMhfAddAchievement struct {
Unk0 uint8
Unk1 uint16
Unk2 uint16
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddAchievement) Opcode() network.PacketID {
return network.MSG_MHF_ADD_ACHIEVEMENT
}
// Parse parses the packet from binary
func (m *MsgMhfAddAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.Unk0 = bf.ReadUint8()
m.Unk1 = bf.ReadUint16()
m.Unk2 = bf.ReadUint16()
// doesn't expect a response
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddAchievement) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint8(m.Unk0)
bf.WriteUint16(m.Unk1)
bf.WriteUint16(m.Unk2)
return nil
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddGuildMissionCount represents the MSG_MHF_ADD_GUILD_MISSION_COUNT
type MsgMhfAddGuildMissionCount struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddGuildMissionCount) Opcode() network.PacketID {
return network.MSG_MHF_ADD_GUILD_MISSION_COUNT
}
// Parse parses the packet from binary
func (m *MsgMhfAddGuildMissionCount) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddGuildMissionCount) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddGuildWeeklyBonusExceptionalUser represents the MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER
type MsgMhfAddGuildWeeklyBonusExceptionalUser struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Opcode() network.PacketID {
return network.MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER
}
// Parse parses the packet from binary
func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,32 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddKouryouPoint represents the MSG_MHF_ADD_KOURYOU_POINT
type MsgMhfAddKouryouPoint struct {
AckHandle uint32
KouryouPoints uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddKouryouPoint) Opcode() network.PacketID {
return network.MSG_MHF_ADD_KOURYOU_POINT
}
// Parse parses the packet from binary
func (m *MsgMhfAddKouryouPoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.KouryouPoints = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddKouryouPoint) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle)
bf.WriteUint32(m.KouryouPoints)
return nil
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddRewardSongCount represents the MSG_MHF_ADD_REWARD_SONG_COUNT
type MsgMhfAddRewardSongCount struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddRewardSongCount) Opcode() network.PacketID {
return network.MSG_MHF_ADD_REWARD_SONG_COUNT
}
// Parse parses the packet from binary
func (m *MsgMhfAddRewardSongCount) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddRewardSongCount) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,36 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddUdPoint represents the MSG_MHF_ADD_UD_POINT
type MsgMhfAddUdPoint struct {
AckHandle uint32
Unk1 uint32
Unk2 uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddUdPoint) Opcode() network.PacketID {
return network.MSG_MHF_ADD_UD_POINT
}
// Parse parses the packet from binary
func (m *MsgMhfAddUdPoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk1 = bf.ReadUint32()
m.Unk2 = bf.ReadUint32()
return nil
//panic("Not implemented")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddUdPoint) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,35 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAddUdTacticsPoint represents the MSG_MHF_ADD_UD_TACTICS_POINT
type MsgMhfAddUdTacticsPoint struct {
AckHandle uint32
Unk0 uint16
Unk1 uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddUdTacticsPoint) Opcode() network.PacketID {
return network.MSG_MHF_ADD_UD_TACTICS_POINT
}
// Parse parses the packet from binary
func (m *MsgMhfAddUdTacticsPoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
m.Unk1 = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAddUdTacticsPoint) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle)
bf.WriteUint16(m.Unk0)
bf.WriteUint32(m.Unk1)
return nil
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAnnounce represents the MSG_MHF_ANNOUNCE
type MsgMhfAnnounce struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAnnounce) Opcode() network.PacketID {
return network.MSG_MHF_ANNOUNCE
}
// Parse parses the packet from binary
func (m *MsgMhfAnnounce) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAnnounce) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,34 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfAnswerGuildScout represents the MSG_MHF_ANSWER_GUILD_SCOUT
type MsgMhfAnswerGuildScout struct {
AckHandle uint32
LeaderID uint32
Answer bool
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfAnswerGuildScout) Opcode() network.PacketID {
return network.MSG_MHF_ANSWER_GUILD_SCOUT
}
// Parse parses the packet from binary
func (m *MsgMhfAnswerGuildScout) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.LeaderID = bf.ReadUint32()
m.Answer = bf.ReadBool()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfAnswerGuildScout) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfApplyBbsArticle represents the MSG_MHF_APPLY_BBS_ARTICLE
type MsgMhfApplyBbsArticle struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfApplyBbsArticle) Opcode() network.PacketID {
return network.MSG_MHF_APPLY_BBS_ARTICLE
}
// Parse parses the packet from binary
func (m *MsgMhfApplyBbsArticle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfApplyBbsArticle) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,38 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfApplyCampaign represents the MSG_MHF_APPLY_CAMPAIGN
type MsgMhfApplyCampaign struct {
AckHandle uint32
Unk0 uint8
Unk1 uint8
Unk2 uint16
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfApplyCampaign) Opcode() network.PacketID {
return network.MSG_MHF_APPLY_CAMPAIGN
}
// Parse parses the packet from binary
func (m *MsgMhfApplyCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
m.Unk1 = bf.ReadUint8()
m.Unk2 = bf.ReadUint16()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfApplyCampaign) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle)
bf.WriteUint8(m.Unk0)
bf.WriteUint8(m.Unk1)
bf.WriteUint16(m.Unk2)
return nil
}

View File

@@ -0,0 +1,41 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfApplyDistItem represents the MSG_MHF_APPLY_DIST_ITEM
type MsgMhfApplyDistItem struct {
AckHandle uint32
Unk0 uint8
RequestType uint32
Unk2 uint32
Unk3 uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfApplyDistItem) Opcode() network.PacketID {
return network.MSG_MHF_APPLY_DIST_ITEM
}
// Parse parses the packet from binary
func (m *MsgMhfApplyDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
m.RequestType = bf.ReadUint32()
m.Unk2 = bf.ReadUint32()
m.Unk3 = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfApplyDistItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle)
bf.WriteUint8(m.Unk0)
bf.WriteUint32(m.RequestType)
bf.WriteUint32(m.Unk2)
bf.WriteUint32(m.Unk3)
return nil
}

View File

@@ -0,0 +1,47 @@
package mhfpacket
import (
"github.com/Solenataris/Erupe/network"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfArrangeGuildMember represents the MSG_MHF_ARRANGE_GUILD_MEMBER
type MsgMhfArrangeGuildMember struct {
AckHandle uint32
GuildID uint32
CharIDs []uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfArrangeGuildMember) Opcode() network.PacketID {
return network.MSG_MHF_ARRANGE_GUILD_MEMBER
}
// Parse parses the packet from binary
func (m *MsgMhfArrangeGuildMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
charCount := bf.ReadUint16()
m.CharIDs = make([]uint32, charCount)
for i := uint16(0); i < charCount; i++ {
m.CharIDs[i] = bf.ReadUint32()
}
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfArrangeGuildMember) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle)
bf.WriteUint32(m.GuildID)
bf.WriteUint16(uint16(len(m.CharIDs)))
for _, charID := range m.CharIDs {
bf.WriteUint32(charID)
}
return nil
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfCancelGuildMissionTarget represents the MSG_MHF_CANCEL_GUILD_MISSION_TARGET
type MsgMhfCancelGuildMissionTarget struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfCancelGuildMissionTarget) Opcode() network.PacketID {
return network.MSG_MHF_CANCEL_GUILD_MISSION_TARGET
}
// Parse parses the packet from binary
func (m *MsgMhfCancelGuildMissionTarget) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfCancelGuildMissionTarget) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,32 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfCancelGuildScout represents the MSG_MHF_CANCEL_GUILD_SCOUT
type MsgMhfCancelGuildScout struct {
AckHandle uint32
InvitationID uint32
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfCancelGuildScout) Opcode() network.PacketID {
return network.MSG_MHF_CANCEL_GUILD_SCOUT
}
// Parse parses the packet from binary
func (m *MsgMhfCancelGuildScout) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.InvitationID = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfCancelGuildScout) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfCaravanMyRank represents the MSG_MHF_CARAVAN_MY_RANK
type MsgMhfCaravanMyRank struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfCaravanMyRank) Opcode() network.PacketID {
return network.MSG_MHF_CARAVAN_MY_RANK
}
// Parse parses the packet from binary
func (m *MsgMhfCaravanMyRank) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfCaravanMyRank) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfCaravanMyScore represents the MSG_MHF_CARAVAN_MY_SCORE
type MsgMhfCaravanMyScore struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfCaravanMyScore) Opcode() network.PacketID {
return network.MSG_MHF_CARAVAN_MY_SCORE
}
// Parse parses the packet from binary
func (m *MsgMhfCaravanMyScore) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfCaravanMyScore) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -0,0 +1,27 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfCaravanRanking represents the MSG_MHF_CARAVAN_RANKING
type MsgMhfCaravanRanking struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfCaravanRanking) Opcode() network.PacketID {
return network.MSG_MHF_CARAVAN_RANKING
}
// Parse parses the packet from binary
func (m *MsgMhfCaravanRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgMhfCaravanRanking) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

Some files were not shown because too many files have changed in this diff Show More