Config / DB now its own package

This commit is contained in:
stratic-dev
2024-10-12 22:37:42 +01:00
parent 44692e986e
commit 5f975c97b5
76 changed files with 3249 additions and 2359 deletions

View File

@@ -1,4 +1,4 @@
package _config package config
import ( import (
"fmt" "fmt"
@@ -6,6 +6,7 @@ import (
"net" "net"
"os" "os"
"strings" "strings"
"sync"
"time" "time"
"github.com/spf13/viper" "github.com/spf13/viper"
@@ -299,15 +300,10 @@ type EntranceChannelInfo struct {
CurrentPlayers uint16 CurrentPlayers uint16
} }
var ErupeConfig *Config var (
once sync.Once
func init() { ErupeConfig *Config
var err error )
ErupeConfig, err = LoadConfig()
if err != nil {
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
}
}
// getOutboundIP4 gets the preferred outbound ip4 of this machine // getOutboundIP4 gets the preferred outbound ip4 of this machine
// From https://stackoverflow.com/a/37382208 // From https://stackoverflow.com/a/37382208
@@ -368,7 +364,16 @@ func LoadConfig() (*Config, error) {
return c, nil return c, nil
} }
func GetConfig() *Config {
once.Do(func() {
var err error
ErupeConfig, err = LoadConfig()
if err != nil {
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
}
})
return ErupeConfig
}
func preventClose(text string) { func preventClose(text string) {
if ErupeConfig.DisableSoftCrash { if ErupeConfig.DisableSoftCrash {
os.Exit(0) os.Exit(0)

176
main.go
View File

@@ -1,7 +1,7 @@
package main package main
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"fmt" "fmt"
"net" "net"
"os" "os"
@@ -13,27 +13,19 @@ import (
"erupe-ce/server/api" "erupe-ce/server/api"
"erupe-ce/server/channelserver" "erupe-ce/server/channelserver"
"erupe-ce/server/discordbot" "erupe-ce/server/discordbot"
"erupe-ce/server/entranceserver" "erupe-ce/server/entrance"
"erupe-ce/server/sign"
"erupe-ce/utils/db"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"erupe-ce/server/signserver"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" _ "github.com/lib/pq"
"go.uber.org/zap" "go.uber.org/zap"
) )
var mainLogger logger.Logger var mainLogger logger.Logger
// 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 users")
}
var Commit = func() string { var Commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok { if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings { for _, setting := range info.Settings {
@@ -54,96 +46,24 @@ func initLogger() {
mainLogger = logger.Get().Named("main") mainLogger = logger.Get().Named("main")
} }
func main() { func main() {
var err error var err error
config := _config.ErupeConfig config := config.GetConfig()
initLogger() initLogger()
mainLogger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit())) mainLogger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit()))
mainLogger.Info(fmt.Sprintf("Client Mode: %s (%d)", config.ClientMode, config.ClientID)) mainLogger.Info(fmt.Sprintf("Client Mode: %s (%d)", config.ClientMode, config.ClientID))
if config.Database.Password == "" { checkAndExitIf(config.Database.Password == "", "Database password is blank")
preventClose("Database password is blank")
}
if net.ParseIP(config.Host) == nil { resolveHostIP()
ips, _ := net.LookupIP(config.Host)
for _, ip := range ips {
if ip != nil {
config.Host = ip.String()
break
}
}
if net.ParseIP(config.Host) == nil {
preventClose("Invalid host address")
}
}
// Discord bot discordBot := initializeDiscordBot()
var discordBot *discordbot.DiscordBot = nil
if config.Discord.Enabled { database, err := db.InitDB(config)
bot, err := discordbot.NewDiscordBot(discordbot.Options{
Config: _config.ErupeConfig,
})
DiscordFailMsg := "Discord: Failed to start, %s"
if err != nil { if err != nil {
preventClose(fmt.Sprintf(DiscordFailMsg, err.Error())) mainLogger.Fatal(fmt.Sprintf("Database initialization failed: %s", err))
}
// Discord bot
err = bot.Start()
if err != nil {
preventClose(fmt.Sprintf(DiscordFailMsg, err.Error()))
}
discordBot = bot
_, err = discordBot.Session.ApplicationCommandBulkOverwrite(discordBot.Session.State.User.ID, "", discordbot.Commands)
if err != nil {
preventClose(fmt.Sprintf(DiscordFailMsg, err.Error()))
}
mainLogger.Info("Discord: Started successfully")
} else {
mainLogger.Info("Discord: Disabled")
}
// Create the postgres DB pool.
connectString := fmt.Sprintf(
"host='%s' port='%d' user='%s' password='%s' dbname='%s' sslmode=disable",
config.Database.Host,
config.Database.Port,
config.Database.User,
config.Database.Password,
config.Database.Database,
)
db, err := sqlx.Open("postgres", connectString)
if err != nil {
preventClose(fmt.Sprintf("Database: Failed to open, %s", err.Error()))
}
// Test the DB connection.
err = db.Ping()
if err != nil {
preventClose(fmt.Sprintf("Database: Failed to ping, %s", err.Error()))
}
mainLogger.Info("Database: Started successfully")
// Clear stale data
if config.DebugOptions.ProxyPort == 0 {
_ = db.MustExec("DELETE FROM sign_sessions")
}
_ = db.MustExec("DELETE FROM servers")
_ = db.MustExec(`UPDATE guild_characters SET treasure_hunt=NULL`)
// Clean the DB if the option is on.
if config.DebugOptions.CleanDB {
mainLogger.Info("Database: Started clearing...")
cleanDB(db)
mainLogger.Info("Database: Finished clearing")
} }
mainLogger.Info(fmt.Sprintf("Server Time: %s", gametime.TimeAdjusted().String())) mainLogger.Info(fmt.Sprintf("Server Time: %s", gametime.TimeAdjusted().String()))
@@ -151,16 +71,10 @@ func main() {
// Now start our server(s). // Now start our server(s).
// Entrance server. // Entrance server.
entranceLogger := logger.Get().Named("entrance")
var entranceServer *entranceserver.Server var entranceServer *entrance.EntranceServer
if config.Entrance.Enabled { if config.Entrance.Enabled {
entranceServer = entranceserver.NewServer( entranceServer = entrance.NewServer()
&entranceserver.Config{
Logger: entranceLogger,
ErupeConfig: _config.ErupeConfig,
DB: db,
})
err = entranceServer.Start() err = entranceServer.Start()
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Entrance: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf("Entrance: Failed to start, %s", err.Error()))
@@ -171,13 +85,9 @@ func main() {
} }
// Sign server. // Sign server.
var signServer *signserver.Server var signServer *sign.SignServer
if config.Sign.Enabled { if config.Sign.Enabled {
signServer = signserver.NewServer( signServer = sign.NewServer()
&signserver.Config{
ErupeConfig: _config.ErupeConfig,
DB: db,
})
err = signServer.Start() err = signServer.Start()
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Sign: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf("Sign: Failed to start, %s", err.Error()))
@@ -188,14 +98,10 @@ func main() {
} }
// Api server // Api server
var ApiServer *api.APIServer var apiServer *api.APIServer
if config.API.Enabled { if config.API.Enabled {
ApiServer = api.NewAPIServer( apiServer = api.NewAPIServer()
&api.Config{ err = apiServer.Start()
ErupeConfig: _config.ErupeConfig,
DB: db,
})
err = ApiServer.Start()
if err != nil { if err != nil {
preventClose(fmt.Sprintf("API: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf("API: Failed to start, %s", err.Error()))
} }
@@ -203,8 +109,7 @@ func main() {
} else { } else {
mainLogger.Info("API: Disabled") mainLogger.Info("API: Disabled")
} }
var channelServers []*channelserver.ChannelServer
var channelServers []*channelserver.Server
if config.Channel.Enabled { if config.Channel.Enabled {
channelQuery := "" channelQuery := ""
si := 0 si := 0
@@ -215,8 +120,6 @@ func main() {
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),
ErupeConfig: _config.ErupeConfig,
DB: db,
DiscordBot: discordBot, DiscordBot: discordBot,
}) })
if ee.IP == "" { if ee.IP == "" {
@@ -242,7 +145,7 @@ func main() {
} }
// Register all servers in DB // Register all servers in DB
_ = db.MustExec(channelQuery) _ = database.MustExec(channelQuery)
for _, c := range channelServers { for _, c := range channelServers {
c.Channels = channelServers c.Channels = channelServers
@@ -278,7 +181,7 @@ func main() {
} }
if config.API.Enabled { if config.API.Enabled {
ApiServer.Shutdown() apiServer.Shutdown()
} }
if config.Entrance.Enabled { if config.Entrance.Enabled {
@@ -295,7 +198,7 @@ func wait() {
} }
func preventClose(text string) { func preventClose(text string) {
if _config.ErupeConfig.DisableSoftCrash { if config.GetConfig().DisableSoftCrash {
os.Exit(0) os.Exit(0)
} }
mainLogger.Error(fmt.Sprintf(("\nFailed to start Erupe:\n" + text))) mainLogger.Error(fmt.Sprintf(("\nFailed to start Erupe:\n" + text)))
@@ -303,3 +206,38 @@ func preventClose(text string) {
mainLogger.Error(fmt.Sprintf(("\nPress Enter/Return to exit..."))) mainLogger.Error(fmt.Sprintf(("\nPress Enter/Return to exit...")))
os.Exit(0) os.Exit(0)
} }
func checkAndExitIf(condition bool, message string) {
if condition {
preventClose(message)
}
}
func resolveHostIP() {
if net.ParseIP(config.GetConfig().Host) == nil {
ips, err := net.LookupIP(config.GetConfig().Host)
if err == nil && len(ips) > 0 {
config.GetConfig().Host = ips[0].String()
}
checkAndExitIf(net.ParseIP(config.GetConfig().Host) == nil, "Invalid host address")
}
}
func initializeDiscordBot() *discordbot.DiscordBot {
if !config.GetConfig().Discord.Enabled {
mainLogger.Info("Discord: Disabled")
return nil
}
bot, err := discordbot.NewDiscordBot()
checkAndExitIf(err != nil, fmt.Sprintf("Discord: Failed to start, %s", err))
err = bot.Start()
checkAndExitIf(err != nil, fmt.Sprintf("Discord: Failed to start, %s", err))
_, err = bot.Session.ApplicationCommandBulkOverwrite(bot.Session.State.User.ID, "", discordbot.Commands)
checkAndExitIf(err != nil, fmt.Sprintf("Discord: Failed to register commands, %s", err))
mainLogger.Info("Discord: Started successfully")
return bot
}

View File

@@ -3,7 +3,7 @@ package network
import ( import (
"encoding/hex" "encoding/hex"
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/crypto" "erupe-ce/network/crypto"
"fmt" "fmt"
"io" "io"
@@ -51,7 +51,7 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) {
var encryptedPacketBody []byte var encryptedPacketBody []byte
// Don't know when support for this was added, works in Forward.4, doesn't work in Season 6.0 // Don't know when support for this was added, works in Forward.4, doesn't work in Season 6.0
if _config.ErupeConfig.ClientID < _config.F1 { if config.GetConfig().ClientID < config.F1 {
encryptedPacketBody = make([]byte, cph.DataSize) encryptedPacketBody = make([]byte, cph.DataSize)
} else { } else {
encryptedPacketBody = make([]byte, uint32(cph.DataSize)+(uint32(cph.Pf0-0x03)*0x1000)) encryptedPacketBody = make([]byte, uint32(cph.DataSize)+(uint32(cph.Pf0-0x03)*0x1000))

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -30,7 +30,7 @@ func (m *MsgMhfAcquireCafeItem) Parse(bf *byteframe.ByteFrame) error {
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.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
m.PointCost = bf.ReadUint32() m.PointCost = bf.ReadUint32()
} else { } else {
m.PointCost = uint32(bf.ReadUint16()) m.PointCost = uint32(bf.ReadUint16())

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
) )
@@ -26,10 +26,10 @@ func (m *MsgMhfApplyDistItem) Parse(bf *byteframe.ByteFrame) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.DistributionType = bf.ReadUint8() m.DistributionType = bf.ReadUint8()
m.DistributionID = bf.ReadUint32() m.DistributionID = bf.ReadUint32()
if _config.ErupeConfig.ClientID >= _config.G8 { if config.GetConfig().ClientID >= config.G8 {
m.Unk2 = bf.ReadUint32() m.Unk2 = bf.ReadUint32()
} }
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
m.Unk3 = bf.ReadUint32() m.Unk3 = bf.ReadUint32()
} }
return nil return nil

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
) )
@@ -27,7 +27,7 @@ func (m *MsgMhfEnumerateDistItem) Parse(bf *byteframe.ByteFrame) error {
m.DistType = bf.ReadUint8() m.DistType = bf.ReadUint8()
m.Unk1 = bf.ReadUint8() m.Unk1 = bf.ReadUint8()
m.Unk2 = bf.ReadUint16() // Maximum? Hardcoded to 256 m.Unk2 = bf.ReadUint16() // Maximum? Hardcoded to 256
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8())) m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8()))
} }
return nil return nil

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -29,7 +29,7 @@ func (m *MsgMhfEnumerateQuest) Parse(bf *byteframe.ByteFrame) error {
m.Unk0 = bf.ReadUint8() m.Unk0 = bf.ReadUint8()
m.World = bf.ReadUint8() m.World = bf.ReadUint8()
m.Counter = bf.ReadUint16() m.Counter = bf.ReadUint16()
if _config.ErupeConfig.ClientID <= _config.Z1 { if config.GetConfig().ClientID <= config.Z1 {
m.Offset = uint16(bf.ReadUint8()) m.Offset = uint16(bf.ReadUint8())
} else { } else {
m.Offset = bf.ReadUint16() m.Offset = bf.ReadUint16()

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -31,7 +31,7 @@ func (m *MsgMhfEnumerateShop) Parse(bf *byteframe.ByteFrame) error {
m.ShopID = bf.ReadUint32() m.ShopID = bf.ReadUint32()
m.Limit = bf.ReadUint16() m.Limit = bf.ReadUint16()
m.Unk3 = bf.ReadUint8() m.Unk3 = bf.ReadUint8()
if _config.ErupeConfig.ClientID >= _config.G2 { if config.GetConfig().ClientID >= config.G2 {
m.Unk4 = bf.ReadUint8() m.Unk4 = bf.ReadUint8()
m.Unk5 = bf.ReadUint32() m.Unk5 = bf.ReadUint32()
} }

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -29,7 +29,7 @@ func (m *MsgMhfSavedata) Parse(bf *byteframe.ByteFrame) error {
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.ClientID >= _config.G1 { if config.GetConfig().ClientID >= 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?

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -31,12 +31,12 @@ func (m *MsgMhfStampcardStamp) Opcode() network.PacketID {
func (m *MsgMhfStampcardStamp) Parse(bf *byteframe.ByteFrame) error { func (m *MsgMhfStampcardStamp) Parse(bf *byteframe.ByteFrame) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.HR = bf.ReadUint16() m.HR = bf.ReadUint16()
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
m.GR = bf.ReadUint16() m.GR = bf.ReadUint16()
} }
m.Stamps = bf.ReadUint16() m.Stamps = bf.ReadUint16()
bf.ReadUint16() // Zeroed bf.ReadUint16() // Zeroed
if _config.ErupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
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())

View File

@@ -3,7 +3,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
) )
@@ -22,11 +22,11 @@ func (m *MsgMhfUpdateMyhouseInfo) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfUpdateMyhouseInfo) Parse(bf *byteframe.ByteFrame) error { func (m *MsgMhfUpdateMyhouseInfo) Parse(bf *byteframe.ByteFrame) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
m.Data = bf.ReadBytes(362) m.Data = bf.ReadBytes(362)
} else if _config.ErupeConfig.ClientID >= _config.GG { } else if config.GetConfig().ClientID >= config.GG {
m.Data = bf.ReadBytes(338) m.Data = bf.ReadBytes(338)
} else if _config.ErupeConfig.ClientID >= _config.F5 { } else if config.GetConfig().ClientID >= config.F5 {
// G1 is a guess // G1 is a guess
m.Data = bf.ReadBytes(314) m.Data = bf.ReadBytes(314)
} else { } else {

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
) )
@@ -24,7 +24,7 @@ func (m *MsgSysCreateAcquireSemaphore) Opcode() network.PacketID {
func (m *MsgSysCreateAcquireSemaphore) Parse(bf *byteframe.ByteFrame) error { func (m *MsgSysCreateAcquireSemaphore) Parse(bf *byteframe.ByteFrame) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16() m.Unk0 = bf.ReadUint16()
if _config.ErupeConfig.ClientID >= _config.S7 { // Assuming this was added with Ravi? if config.GetConfig().ClientID >= config.S7 { // Assuming this was added with Ravi?
m.PlayerCount = bf.ReadUint8() m.PlayerCount = bf.ReadUint8()
} }
bf.ReadUint8() // SemaphoreID length bf.ReadUint8() // SemaphoreID length

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -25,7 +25,7 @@ func (m *MsgSysCreateSemaphore) Opcode() network.PacketID {
func (m *MsgSysCreateSemaphore) Parse(bf *byteframe.ByteFrame) error { func (m *MsgSysCreateSemaphore) Parse(bf *byteframe.ByteFrame) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16() m.Unk0 = bf.ReadUint16()
if _config.ErupeConfig.ClientID >= _config.S7 { // Assuming this was added with Ravi? if config.GetConfig().ClientID >= config.S7 { // Assuming this was added with Ravi?
m.PlayerCount = bf.ReadUint8() m.PlayerCount = bf.ReadUint8()
} }
bf.ReadUint8() // SemaphoreID length bf.ReadUint8() // SemaphoreID length

View File

@@ -2,7 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
@@ -48,7 +48,7 @@ func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame) error {
e.Unk1 = bf.ReadInt32() e.Unk1 = bf.ReadInt32()
e.Unk2 = bf.ReadInt32() e.Unk2 = bf.ReadInt32()
e.Unk3 = bf.ReadInt32() e.Unk3 = bf.ReadInt32()
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
for j := 0; j < 4; j++ { for j := 0; j < 4; j++ {
e.Unk4 = append(e.Unk4, bf.ReadInt32()) e.Unk4 = append(e.Unk4, bf.ReadInt32())
} }

View File

@@ -2,7 +2,7 @@ package api
import ( import (
"context" "context"
_config "erupe-ce/config" "erupe-ce/config"
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
@@ -13,32 +13,23 @@ import (
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
) )
type Config struct {
DB *sqlx.DB
ErupeConfig *_config.Config
}
// APIServer is Erupes Standard API interface // APIServer is Erupes Standard API interface
type APIServer struct { type APIServer struct {
sync.Mutex sync.Mutex
logger logger.Logger logger logger.Logger
erupeConfig *_config.Config erupeConfig *config.Config
db *sqlx.DB
httpServer *http.Server httpServer *http.Server
isShuttingDown bool isShuttingDown bool
} }
// NewAPIServer creates a new Server type. // NewAPIServer creates a new Server type.
func NewAPIServer(config *Config) *APIServer { func NewAPIServer() *APIServer {
s := &APIServer{ s := &APIServer{
logger: logger.Get().Named("API"), logger: logger.Get().Named("API"),
erupeConfig: config.ErupeConfig,
db: config.DB,
httpServer: &http.Server{}, httpServer: &http.Server{},
} }
return s return s
@@ -58,7 +49,7 @@ func (s *APIServer) Start() error {
r.HandleFunc("/api/ss/bbs/{id}", s.ScreenShotGet) r.HandleFunc("/api/ss/bbs/{id}", s.ScreenShotGet)
handler := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))(r) handler := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))(r)
s.httpServer.Handler = handlers.LoggingHandler(os.Stdout, handler) s.httpServer.Handler = handlers.LoggingHandler(os.Stdout, handler)
s.httpServer.Addr = fmt.Sprintf(":%d", s.erupeConfig.API.Port) s.httpServer.Addr = fmt.Sprintf(":%d", config.GetConfig().API.Port)
serveError := make(chan error, 1) serveError := make(chan error, 1)
go func() { go func() {

View File

@@ -3,6 +3,7 @@ package api
import ( import (
"context" "context"
"database/sql" "database/sql"
"erupe-ce/utils/db"
"erupe-ce/utils/token" "erupe-ce/utils/token"
"fmt" "fmt"
"time" "time"
@@ -21,7 +22,11 @@ func (s *APIServer) createNewUser(ctx context.Context, username string, password
id uint32 id uint32
rights uint32 rights uint32
) )
err = s.db.QueryRowContext( database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRowContext(
ctx, ` ctx, `
INSERT INTO users (username, password, return_expires) INSERT INTO users (username, password, return_expires)
VALUES ($1, $2, $3) VALUES ($1, $2, $3)
@@ -35,7 +40,11 @@ func (s *APIServer) createNewUser(ctx context.Context, username string, password
func (s *APIServer) createLoginToken(ctx context.Context, uid uint32) (uint32, string, error) { func (s *APIServer) createLoginToken(ctx context.Context, uid uint32) (uint32, string, error) {
loginToken := token.Generate(16) loginToken := token.Generate(16)
var tid uint32 var tid uint32
err := s.db.QueryRowContext(ctx, "INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2) RETURNING id", uid, loginToken).Scan(&tid) database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRowContext(ctx, "INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2) RETURNING id", uid, loginToken).Scan(&tid)
if err != nil { if err != nil {
return 0, "", err return 0, "", err
} }
@@ -44,7 +53,11 @@ func (s *APIServer) createLoginToken(ctx context.Context, uid uint32) (uint32, s
func (s *APIServer) userIDFromToken(ctx context.Context, token string) (uint32, error) { func (s *APIServer) userIDFromToken(ctx context.Context, token string) (uint32, error) {
var userID uint32 var userID uint32
err := s.db.QueryRowContext(ctx, "SELECT user_id FROM sign_sessions WHERE token = $1", token).Scan(&userID) database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRowContext(ctx, "SELECT user_id FROM sign_sessions WHERE token = $1", token).Scan(&userID)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return 0, fmt.Errorf("invalid login token") return 0, fmt.Errorf("invalid login token")
} else if err != nil { } else if err != nil {
@@ -55,17 +68,21 @@ func (s *APIServer) userIDFromToken(ctx context.Context, token string) (uint32,
func (s *APIServer) createCharacter(ctx context.Context, userID uint32) (Character, error) { func (s *APIServer) createCharacter(ctx context.Context, userID uint32) (Character, error) {
var character Character var character Character
err := s.db.GetContext(ctx, &character, database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.GetContext(ctx, &character,
"SELECT id, name, is_female, weapon_type, hr, gr, last_login FROM characters WHERE is_new_character = true AND user_id = $1 LIMIT 1", "SELECT id, name, is_female, weapon_type, hr, gr, last_login FROM characters WHERE is_new_character = true AND user_id = $1 LIMIT 1",
userID, userID,
) )
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
var count int var count int
s.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM characters WHERE user_id = $1", userID).Scan(&count) database.QueryRowContext(ctx, "SELECT COUNT(*) FROM characters WHERE user_id = $1", userID).Scan(&count)
if count >= 16 { if count >= 16 {
return character, fmt.Errorf("cannot have more than 16 characters") return character, fmt.Errorf("cannot have more than 16 characters")
} }
err = s.db.GetContext(ctx, &character, ` err = database.GetContext(ctx, &character, `
INSERT INTO characters ( INSERT INTO characters (
user_id, is_female, is_new_character, name, unk_desc_string, user_id, is_female, is_new_character, name, unk_desc_string,
hr, gr, weapon_type, last_login hr, gr, weapon_type, last_login
@@ -80,21 +97,29 @@ func (s *APIServer) createCharacter(ctx context.Context, userID uint32) (Charact
func (s *APIServer) deleteCharacter(ctx context.Context, userID uint32, charID uint32) error { func (s *APIServer) deleteCharacter(ctx context.Context, userID uint32, charID uint32) error {
var isNew bool var isNew bool
err := s.db.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", charID).Scan(&isNew) database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", charID).Scan(&isNew)
if err != nil { if err != nil {
return err return err
} }
if isNew { if isNew {
_, err = s.db.Exec("DELETE FROM characters WHERE id = $1", charID) _, err = database.Exec("DELETE FROM characters WHERE id = $1", charID)
} else { } else {
_, err = s.db.Exec("UPDATE characters SET deleted = true WHERE id = $1", charID) _, err = database.Exec("UPDATE characters SET deleted = true WHERE id = $1", charID)
} }
return err return err
} }
func (s *APIServer) getCharactersForUser(ctx context.Context, uid uint32) ([]Character, error) { func (s *APIServer) getCharactersForUser(ctx context.Context, uid uint32) ([]Character, error) {
var characters []Character var characters []Character
err := s.db.SelectContext( database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.SelectContext(
ctx, &characters, ` ctx, &characters, `
SELECT id, name, is_female, weapon_type, hr, gr, last_login SELECT id, name, is_female, weapon_type, hr, gr, last_login
FROM characters FROM characters
@@ -109,25 +134,33 @@ func (s *APIServer) getCharactersForUser(ctx context.Context, uid uint32) ([]Cha
func (s *APIServer) getReturnExpiry(uid uint32) time.Time { func (s *APIServer) getReturnExpiry(uid uint32) time.Time {
var returnExpiry, lastLogin time.Time var returnExpiry, lastLogin time.Time
s.db.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid) database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid)
if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) { if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) {
returnExpiry = time.Now().Add(time.Hour * 24 * 30) returnExpiry = time.Now().Add(time.Hour * 24 * 30)
s.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid) database.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
} else { } else {
err := s.db.Get(&returnExpiry, "SELECT return_expires FROM users WHERE id=$1", uid) err := database.Get(&returnExpiry, "SELECT return_expires FROM users WHERE id=$1", uid)
if err != nil { if err != nil {
returnExpiry = time.Now() returnExpiry = time.Now()
s.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid) database.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
} }
} }
s.db.Exec("UPDATE users SET last_login=$1 WHERE id=$2", time.Now(), uid) database.Exec("UPDATE users SET last_login=$1 WHERE id=$2", time.Now(), uid)
return returnExpiry return returnExpiry
} }
func (s *APIServer) exportSave(ctx context.Context, uid uint32, cid uint32) (map[string]interface{}, error) { func (s *APIServer) exportSave(ctx context.Context, uid uint32, cid uint32) (map[string]interface{}, error) {
row := s.db.QueryRowxContext(ctx, "SELECT * FROM characters WHERE id=$1 AND user_id=$2", cid, uid) database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
row := database.QueryRowxContext(ctx, "SELECT * FROM characters WHERE id=$1 AND user_id=$2", cid, uid)
result := make(map[string]interface{}) result := make(map[string]interface{})
err := row.MapScan(result) err = row.MapScan(result)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -5,7 +5,8 @@ import (
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"fmt" "fmt"
"image" "image"
@@ -30,9 +31,9 @@ const (
) )
type LauncherResponse struct { type LauncherResponse struct {
Banners []_config.APISignBanner `json:"banners"` Banners []config.APISignBanner `json:"banners"`
Messages []_config.APISignMessage `json:"messages"` Messages []config.APISignMessage `json:"messages"`
Links []_config.APISignLink `json:"links"` Links []config.APISignLink `json:"links"`
} }
type User struct { type User struct {
@@ -137,7 +138,11 @@ func (s *APIServer) Login(w http.ResponseWriter, r *http.Request) {
userRights uint32 userRights uint32
password string password string
) )
err := s.db.QueryRow("SELECT id, password, rights FROM users WHERE username = $1", reqData.Username).Scan(&userID, &password, &userRights) database, err := db.GetDB()
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT id, password, rights FROM users WHERE username = $1", reqData.Username).Scan(&userID, &password, &userRights)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
w.WriteHeader(400) w.WriteHeader(400)
w.Write([]byte("username-error")) w.Write([]byte("username-error"))

View File

@@ -1,23 +1,24 @@
package channelserver package channelserver
import ( import (
"erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
) )
func doAckEarthSucceed(s *Session, ackHandle uint32, data []*byteframe.ByteFrame) { func DoAckEarthSucceed(s *Session, ackHandle uint32, data []*byteframe.ByteFrame) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(uint32(s.server.erupeConfig.EarthID)) bf.WriteUint32(uint32(config.GetConfig().EarthID))
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(uint32(len(data))) bf.WriteUint32(uint32(len(data)))
for i := range data { for i := range data {
bf.WriteBytes(data[i].Data()) bf.WriteBytes(data[i].Data())
} }
doAckBufSucceed(s, ackHandle, bf.Data()) DoAckBufSucceed(s, ackHandle, bf.Data())
} }
func doAckBufSucceed(s *Session, ackHandle uint32, data []byte) { func DoAckBufSucceed(s *Session, ackHandle uint32, data []byte) {
s.QueueSendMHF(&mhfpacket.MsgSysAck{ s.QueueSendMHF(&mhfpacket.MsgSysAck{
AckHandle: ackHandle, AckHandle: ackHandle,
IsBufferResponse: true, IsBufferResponse: true,
@@ -26,7 +27,7 @@ func doAckBufSucceed(s *Session, ackHandle uint32, data []byte) {
}) })
} }
func doAckBufFail(s *Session, ackHandle uint32, data []byte) { func DoAckBufFail(s *Session, ackHandle uint32, data []byte) {
s.QueueSendMHF(&mhfpacket.MsgSysAck{ s.QueueSendMHF(&mhfpacket.MsgSysAck{
AckHandle: ackHandle, AckHandle: ackHandle,
IsBufferResponse: true, IsBufferResponse: true,
@@ -35,7 +36,7 @@ func doAckBufFail(s *Session, ackHandle uint32, data []byte) {
}) })
} }
func doAckSimpleSucceed(s *Session, ackHandle uint32, data []byte) { func DoAckSimpleSucceed(s *Session, ackHandle uint32, data []byte) {
s.QueueSendMHF(&mhfpacket.MsgSysAck{ s.QueueSendMHF(&mhfpacket.MsgSysAck{
AckHandle: ackHandle, AckHandle: ackHandle,
IsBufferResponse: false, IsBufferResponse: false,
@@ -44,7 +45,7 @@ func doAckSimpleSucceed(s *Session, ackHandle uint32, data []byte) {
}) })
} }
func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) { func DoAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
s.QueueSendMHF(&mhfpacket.MsgSysAck{ s.QueueSendMHF(&mhfpacket.MsgSysAck{
AckHandle: ackHandle, AckHandle: ackHandle,
IsBufferResponse: false, IsBufferResponse: false,

View File

@@ -2,7 +2,8 @@ package channelserver
import ( import (
"encoding/binary" "encoding/binary"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/mhfcourse" "erupe-ce/utils/mhfcourse"
"erupe-ce/utils/mhfitem" "erupe-ce/utils/mhfitem"
@@ -28,12 +29,16 @@ func stubEnumerateNoResults(s *Session, ackHandle uint32) {
enumBf := byteframe.NewByteFrame() enumBf := byteframe.NewByteFrame()
enumBf.WriteUint32(0) // Entry count (count for quests, rankings, events, etc.) enumBf.WriteUint32(0) // Entry count (count for quests, rankings, events, etc.)
doAckBufSucceed(s, ackHandle, enumBf.Data()) DoAckBufSucceed(s, ackHandle, enumBf.Data())
} }
func updateRights(s *Session) { func updateRights(s *Session) {
rightsInt := uint32(2) rightsInt := uint32(2)
s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.CharID).Scan(&rightsInt)
s.courses, rightsInt = mhfcourse.GetCourseStruct(rightsInt) s.courses, rightsInt = mhfcourse.GetCourseStruct(rightsInt)
update := &mhfpacket.MsgSysUpdateRight{ update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0, ClientRespAckHandle: 0,
@@ -63,7 +68,7 @@ func handleMsgSysAck(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysTerminalLog) pkt := p.(*mhfpacket.MsgSysTerminalLog)
for i := range pkt.Entries { for i := range pkt.Entries {
s.server.logger.Info("SysTerminalLog", s.Server.logger.Info("SysTerminalLog",
zap.Uint8("Type1", pkt.Entries[i].Type1), zap.Uint8("Type1", pkt.Entries[i].Type1),
zap.Uint8("Type2", pkt.Entries[i].Type2), zap.Uint8("Type2", pkt.Entries[i].Type2),
zap.Int16("Unk0", pkt.Entries[i].Unk0), zap.Int16("Unk0", pkt.Entries[i].Unk0),
@@ -75,55 +80,58 @@ func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) {
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(pkt.LogID + 1) // LogID to use for requests after this. resp.WriteUint32(pkt.LogID + 1) // LogID to use for requests after this.
doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLogin) pkt := p.(*mhfpacket.MsgSysLogin)
database, err := db.GetDB()
if !s.server.erupeConfig.DebugOptions.DisableTokenCheck { if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if !config.GetConfig().DebugOptions.DisableTokenCheck {
var token string var token string
err := s.server.db.QueryRow("SELECT token FROM sign_sessions ss INNER JOIN public.users u on ss.user_id = u.id WHERE token=$1 AND ss.id=$2 AND u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.LoginTokenString, pkt.LoginTokenNumber, pkt.CharID0).Scan(&token) err := database.QueryRow("SELECT token FROM sign_sessions ss INNER JOIN public.users u on ss.user_id = u.id WHERE token=$1 AND ss.id=$2 AND u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.LoginTokenString, pkt.LoginTokenNumber, pkt.CharID0).Scan(&token)
if err != nil { if err != nil {
s.rawConn.Close() s.rawConn.Close()
s.logger.Warn(fmt.Sprintf("Invalid login token, offending CID: (%d)", pkt.CharID0)) s.Logger.Warn(fmt.Sprintf("Invalid login token, offending CID: (%d)", pkt.CharID0))
return return
} }
} }
s.Lock() s.Lock()
s.charID = pkt.CharID0 s.CharID = pkt.CharID0
s.token = pkt.LoginTokenString s.token = pkt.LoginTokenString
s.Unlock() s.Unlock()
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) // Unix timestamp bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) // Unix timestamp
_, err := s.server.db.Exec("UPDATE servers SET current_players=$1 WHERE server_id=$2", len(s.server.sessions), s.server.ID) _, err = database.Exec("UPDATE servers SET current_players=$1 WHERE server_id=$2", len(s.Server.sessions), s.Server.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
_, err = s.server.db.Exec("UPDATE sign_sessions SET server_id=$1, char_id=$2 WHERE token=$3", s.server.ID, s.charID, s.token) _, err = database.Exec("UPDATE sign_sessions SET server_id=$1, char_id=$2 WHERE token=$3", s.Server.ID, s.CharID, s.token)
if err != nil { if err != nil {
panic(err) panic(err)
} }
_, err = s.server.db.Exec("UPDATE characters SET last_login=$1 WHERE id=$2", gametime.TimeAdjusted().Unix(), s.charID) _, err = database.Exec("UPDATE characters SET last_login=$1 WHERE id=$2", gametime.TimeAdjusted().Unix(), s.CharID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
_, err = s.server.db.Exec("UPDATE users u SET last_character=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)", s.charID) _, err = database.Exec("UPDATE users u SET last_character=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)", s.CharID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
updateRights(s) updateRights(s)
s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser{CharID: s.charID}, s) s.Server.BroadcastMHF(&mhfpacket.MsgSysInsertUser{CharID: s.CharID}, s)
} }
func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) {
@@ -131,45 +139,49 @@ func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) {
} }
func logoutPlayer(s *Session) { func logoutPlayer(s *Session) {
s.server.Lock()
if _, exists := s.server.sessions[s.rawConn]; exists { s.Server.Lock()
delete(s.server.sessions, s.rawConn) if _, exists := s.Server.sessions[s.rawConn]; exists {
delete(s.Server.sessions, s.rawConn)
} }
s.rawConn.Close() s.rawConn.Close()
delete(s.server.objectIDs, s) delete(s.Server.objectIDs, s)
s.server.Unlock() s.Server.Unlock()
for _, stage := range s.server.stages { for _, stage := range s.Server.stages {
// Tell sessions registered to disconnecting players quest to unregister // Tell sessions registered to disconnecting players quest to unregister
if stage.host != nil && stage.host.charID == s.charID { if stage.host != nil && stage.host.CharID == s.CharID {
for _, sess := range s.server.sessions { for _, sess := range s.Server.sessions {
for rSlot := range stage.reservedClientSlots { for rSlot := range stage.reservedClientSlots {
if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" { if sess.CharID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" {
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
} }
} }
} }
} }
for session := range stage.clients { for session := range stage.clients {
if session.charID == s.charID { if session.CharID == s.CharID {
delete(stage.clients, session) delete(stage.clients, session)
} }
} }
} }
database, err := db.GetDB()
_, err := s.server.db.Exec("UPDATE sign_sessions SET server_id=NULL, char_id=NULL WHERE token=$1", s.token) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
_, err = database.Exec("UPDATE sign_sessions SET server_id=NULL, char_id=NULL WHERE token=$1", s.token)
if err != nil { if err != nil {
panic(err) panic(err)
} }
_, err = s.server.db.Exec("UPDATE servers SET current_players=$1 WHERE server_id=$2", len(s.server.sessions), s.server.ID) _, err = database.Exec("UPDATE servers SET current_players=$1 WHERE server_id=$2", len(s.Server.sessions), s.Server.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
var timePlayed int var timePlayed int
var sessionTime int var sessionTime int
_ = s.server.db.QueryRow("SELECT time_played FROM characters WHERE id = $1", s.charID).Scan(&timePlayed) _ = database.QueryRow("SELECT time_played FROM characters WHERE id = $1", s.CharID).Scan(&timePlayed)
sessionTime = int(gametime.TimeAdjusted().Unix()) - int(s.sessionStart) sessionTime = int(gametime.TimeAdjusted().Unix()) - int(s.sessionStart)
timePlayed += sessionTime timePlayed += sessionTime
@@ -177,43 +189,43 @@ func logoutPlayer(s *Session) {
if mhfcourse.CourseExists(30, s.courses) { if mhfcourse.CourseExists(30, s.courses) {
rpGained = timePlayed / 900 rpGained = timePlayed / 900
timePlayed = timePlayed % 900 timePlayed = timePlayed % 900
s.server.db.Exec("UPDATE characters SET cafe_time=cafe_time+$1 WHERE id=$2", sessionTime, s.charID) database.Exec("UPDATE characters SET cafe_time=cafe_time+$1 WHERE id=$2", sessionTime, s.CharID)
} else { } else {
rpGained = timePlayed / 1800 rpGained = timePlayed / 1800
timePlayed = timePlayed % 1800 timePlayed = timePlayed % 1800
} }
s.server.db.Exec("UPDATE characters SET time_played = $1 WHERE id = $2", timePlayed, s.charID) database.Exec("UPDATE characters SET time_played = $1 WHERE id = $2", timePlayed, s.CharID)
s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE character_id=$1`, s.charID) database.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE character_id=$1`, s.CharID)
if s.stage == nil { if s.stage == nil {
return return
} }
s.server.BroadcastMHF(&mhfpacket.MsgSysDeleteUser{ s.Server.BroadcastMHF(&mhfpacket.MsgSysDeleteUser{
CharID: s.charID, CharID: s.CharID,
}, s) }, s)
s.server.Lock() s.Server.Lock()
for _, stage := range s.server.stages { for _, stage := range s.Server.stages {
if _, exists := stage.reservedClientSlots[s.charID]; exists { if _, exists := stage.reservedClientSlots[s.CharID]; exists {
delete(stage.reservedClientSlots, s.charID) delete(stage.reservedClientSlots, s.CharID)
} }
} }
s.server.Unlock() s.Server.Unlock()
removeSessionFromSemaphore(s) removeSessionFromSemaphore(s)
removeSessionFromStage(s) removeSessionFromStage(s)
saveData, err := GetCharacterSaveData(s, s.charID) saveData, err := GetCharacterSaveData(s, s.CharID)
if err != nil || saveData == nil { if err != nil || saveData == nil {
s.logger.Error("Failed to get savedata") s.Logger.Error("Failed to get savedata")
return return
} }
saveData.RP += uint16(rpGained) saveData.RP += uint16(rpGained)
if saveData.RP >= s.server.erupeConfig.GameplayOptions.MaximumRP { if saveData.RP >= config.GetConfig().GameplayOptions.MaximumRP {
saveData.RP = s.server.erupeConfig.GameplayOptions.MaximumRP saveData.RP = config.GetConfig().GameplayOptions.MaximumRP
} }
saveData.Save(s) saveData.Save(s)
} }
@@ -222,7 +234,7 @@ func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysPing(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysPing(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysPing) pkt := p.(*mhfpacket.MsgSysPing)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) {
@@ -253,25 +265,29 @@ func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) {
// Issue it. // Issue it.
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteBytes(logKey) resp.WriteBytes(logKey)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysRecordLog) pkt := p.(*mhfpacket.MsgSysRecordLog)
if _config.ErupeConfig.ClientID == _config.ZZ { database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if config.GetConfig().ClientID == config.ZZ {
bf := byteframe.NewByteFrameFromBytes(pkt.Data) bf := byteframe.NewByteFrameFromBytes(pkt.Data)
bf.Seek(32, 0) bf.Seek(32, 0)
var val uint8 var val uint8
for i := 0; i < 176; i++ { for i := 0; i < 176; i++ {
val = bf.ReadUint8() val = bf.ReadUint8()
if val > 0 && mhfmon.Monsters[i].Large { if val > 0 && mhfmon.Monsters[i].Large {
s.server.db.Exec(`INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, $2, $3, $4)`, s.charID, i, val, gametime.TimeAdjusted()) database.Exec(`INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, $2, $3, $4)`, s.CharID, i, val, gametime.TimeAdjusted())
} }
} }
} }
// remove a client returning to town from reserved slots to make sure the stage is hidden from board // remove a client returning to town from reserved slots to make sure the stage is hidden from board
delete(s.stage.reservedClientSlots, s.charID) delete(s.stage.reservedClientSlots, s.CharID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {}
@@ -279,7 +295,7 @@ func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLockGlobalSema) pkt := p.(*mhfpacket.MsgSysLockGlobalSema)
var sgid string var sgid string
for _, channel := range s.server.Channels { for _, channel := range s.Server.Channels {
for id := range channel.stages { for id := range channel.stages {
if strings.HasSuffix(id, pkt.UserIDString) { if strings.HasSuffix(id, pkt.UserIDString) {
sgid = channel.GlobalID sgid = channel.GlobalID
@@ -287,7 +303,7 @@ func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) {
} }
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
if len(sgid) > 0 && sgid != s.server.GlobalID { if len(sgid) > 0 && sgid != s.Server.GlobalID {
bf.WriteUint8(0) bf.WriteUint8(0)
bf.WriteUint8(0) bf.WriteUint8(0)
ps.Uint16(bf, sgid, false) ps.Uint16(bf, sgid, false)
@@ -296,12 +312,12 @@ func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(0) bf.WriteUint8(0)
ps.Uint16(bf, pkt.ServerChannelIDString, false) ps.Uint16(bf, pkt.ServerChannelIDString, false)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgSysUnlockGlobalSema(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysUnlockGlobalSema(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysUnlockGlobalSema) pkt := p.(*mhfpacket.MsgSysUnlockGlobalSema)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgSysUpdateRight(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysUpdateRight(s *Session, p mhfpacket.MHFPacket) {}
@@ -313,7 +329,7 @@ func handleMsgSysAuthTerminal(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysRightsReload(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysRightsReload(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysRightsReload) pkt := p.(*mhfpacket.MsgSysRightsReload)
updateRights(s) updateRights(s)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
@@ -351,18 +367,18 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint16(0) resp.WriteUint16(0)
switch pkt.SearchType { switch pkt.SearchType {
case 1, 2, 3: // usersearchidx, usersearchname, lobbysearchname case 1, 2, 3: // usersearchidx, usersearchname, lobbysearchname
for _, c := range s.server.Channels { for _, c := range s.Server.Channels {
for _, session := range c.sessions { for _, session := range c.sessions {
if count == maxResults { if count == maxResults {
break break
} }
if pkt.SearchType == 1 && session.charID != cid { if pkt.SearchType == 1 && session.CharID != cid {
continue continue
} }
if pkt.SearchType == 2 && !strings.Contains(session.Name, term) { if pkt.SearchType == 2 && !strings.Contains(session.Name, term) {
continue continue
} }
if pkt.SearchType == 3 && session.server.IP != ip && session.server.Port != port && session.stage.id != term { if pkt.SearchType == 3 && session.Server.IP != ip && session.Server.Port != port && session.stage.id != term {
continue continue
} }
count++ count++
@@ -374,13 +390,13 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint32(0x0100007F) resp.WriteUint32(0x0100007F)
} }
resp.WriteUint16(c.Port) resp.WriteUint16(c.Port)
resp.WriteUint32(session.charID) resp.WriteUint32(session.CharID)
resp.WriteUint8(uint8(len(sessionStage) + 1)) resp.WriteUint8(uint8(len(sessionStage) + 1))
resp.WriteUint8(uint8(len(sessionName) + 1)) resp.WriteUint8(uint8(len(sessionName) + 1))
resp.WriteUint16(uint16(len(c.userBinaryParts[userBinaryPartID{charID: session.charID, index: 3}]))) resp.WriteUint16(uint16(len(c.userBinaryParts[userBinaryPartID{charID: session.CharID, index: 3}])))
// TODO: This case might be <=G2 // TODO: This case might be <=G2
if _config.ErupeConfig.ClientID <= _config.G1 { if config.GetConfig().ClientID <= config.G1 {
resp.WriteBytes(make([]byte, 8)) resp.WriteBytes(make([]byte, 8))
} else { } else {
resp.WriteBytes(make([]byte, 40)) resp.WriteBytes(make([]byte, 40))
@@ -389,7 +405,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
resp.WriteNullTerminatedBytes(sessionStage) resp.WriteNullTerminatedBytes(sessionStage)
resp.WriteNullTerminatedBytes(sessionName) resp.WriteNullTerminatedBytes(sessionName)
resp.WriteBytes(c.userBinaryParts[userBinaryPartID{session.charID, 3}]) resp.WriteBytes(c.userBinaryParts[userBinaryPartID{session.CharID, 3}])
} }
} }
case 4: // lobbysearch case 4: // lobbysearch
@@ -411,7 +427,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 0: case 0:
values := bf.ReadUint8() values := bf.ReadUint8()
for i := uint8(0); i < values; i++ { for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
findPartyParams.RankRestriction = bf.ReadInt16() findPartyParams.RankRestriction = bf.ReadInt16()
} else { } else {
findPartyParams.RankRestriction = int16(bf.ReadInt8()) findPartyParams.RankRestriction = int16(bf.ReadInt8())
@@ -420,7 +436,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 1: case 1:
values := bf.ReadUint8() values := bf.ReadUint8()
for i := uint8(0); i < values; i++ { for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
findPartyParams.Targets = append(findPartyParams.Targets, bf.ReadInt16()) findPartyParams.Targets = append(findPartyParams.Targets, bf.ReadInt16())
} else { } else {
findPartyParams.Targets = append(findPartyParams.Targets, int16(bf.ReadInt8())) findPartyParams.Targets = append(findPartyParams.Targets, int16(bf.ReadInt8()))
@@ -430,7 +446,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
values := bf.ReadUint8() values := bf.ReadUint8()
for i := uint8(0); i < values; i++ { for i := uint8(0); i < values; i++ {
var value int16 var value int16
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
value = bf.ReadInt16() value = bf.ReadInt16()
} else { } else {
value = int16(bf.ReadInt8()) value = int16(bf.ReadInt8())
@@ -451,7 +467,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 3: // Unknown case 3: // Unknown
values := bf.ReadUint8() values := bf.ReadUint8()
for i := uint8(0); i < values; i++ { for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
findPartyParams.Unk0 = append(findPartyParams.Unk0, bf.ReadInt16()) findPartyParams.Unk0 = append(findPartyParams.Unk0, bf.ReadInt16())
} else { } else {
findPartyParams.Unk0 = append(findPartyParams.Unk0, int16(bf.ReadInt8())) findPartyParams.Unk0 = append(findPartyParams.Unk0, int16(bf.ReadInt8()))
@@ -460,7 +476,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 4: // Looking for n or already have n case 4: // Looking for n or already have n
values := bf.ReadUint8() values := bf.ReadUint8()
for i := uint8(0); i < values; i++ { for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
findPartyParams.Unk1 = append(findPartyParams.Unk1, bf.ReadInt16()) findPartyParams.Unk1 = append(findPartyParams.Unk1, bf.ReadInt16())
} else { } else {
findPartyParams.Unk1 = append(findPartyParams.Unk1, int16(bf.ReadInt8())) findPartyParams.Unk1 = append(findPartyParams.Unk1, int16(bf.ReadInt8()))
@@ -469,7 +485,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 5: case 5:
values := bf.ReadUint8() values := bf.ReadUint8()
for i := uint8(0); i < values; i++ { for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
findPartyParams.QuestID = append(findPartyParams.QuestID, bf.ReadInt16()) findPartyParams.QuestID = append(findPartyParams.QuestID, bf.ReadInt16())
} else { } else {
findPartyParams.QuestID = append(findPartyParams.QuestID, int16(bf.ReadInt8())) findPartyParams.QuestID = append(findPartyParams.QuestID, int16(bf.ReadInt8()))
@@ -477,7 +493,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
} }
} }
} }
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
@@ -487,15 +503,15 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
sb3.Seek(4, 0) sb3.Seek(4, 0)
stageDataParams := 7 stageDataParams := 7
if _config.ErupeConfig.ClientID <= _config.G10 { if config.GetConfig().ClientID <= config.G10 {
stageDataParams = 4 stageDataParams = 4
} else if _config.ErupeConfig.ClientID <= _config.Z1 { } else if config.GetConfig().ClientID <= config.Z1 {
stageDataParams = 6 stageDataParams = 6
} }
var stageData []int16 var stageData []int16
for i := 0; i < stageDataParams; i++ { for i := 0; i < stageDataParams; i++ {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
stageData = append(stageData, sb3.ReadInt16()) stageData = append(stageData, sb3.ReadInt16())
} else { } else {
stageData = append(stageData, int16(sb3.ReadInt8())) stageData = append(stageData, int16(sb3.ReadInt8()))
@@ -544,7 +560,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint8(uint8(len(stage.rawBinaryData[stageBinaryKey{1, 1}]))) resp.WriteUint8(uint8(len(stage.rawBinaryData[stageBinaryKey{1, 1}])))
for i := range stageData { for i := range stageData {
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
resp.WriteInt16(stageData[i]) resp.WriteInt16(stageData[i])
} else { } else {
resp.WriteInt8(int8(stageData[i])) resp.WriteInt8(int8(stageData[i]))
@@ -562,7 +578,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
} }
resp.Seek(0, io.SeekStart) resp.Seek(0, io.SeekStart)
resp.WriteUint16(count) resp.WriteUint16(count)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {} func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {}
@@ -571,8 +587,8 @@ func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAnnounce) pkt := p.(*mhfpacket.MsgMhfAnnounce)
s.server.BroadcastRaviente(pkt.IPAddress, pkt.Port, pkt.StageID, pkt.Data.ReadUint8()) s.Server.BroadcastRaviente(pkt.IPAddress, pkt.Port, pkt.StageID, pkt.Data.ReadUint8())
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfSetLoginwindow(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfSetLoginwindow(s *Session, p mhfpacket.MHFPacket) {}
@@ -595,7 +611,7 @@ func handleMsgMhfGetCaUniqueID(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})
} }
func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) {
@@ -760,7 +776,7 @@ func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(gz.Unk3) bf.WriteUint16(gz.Unk3)
bf.WriteUint8(gz.Unk4) bf.WriteUint8(gz.Unk4)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfEnumerateOrder(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateOrder(s *Session, p mhfpacket.MHFPacket) {
@@ -773,7 +789,11 @@ func handleMsgMhfGetExtraInfo(s *Session, p mhfpacket.MHFPacket) {}
func userGetItems(s *Session) []mhfitem.MHFItemStack { func userGetItems(s *Session) []mhfitem.MHFItemStack {
var data []byte var data []byte
var items []mhfitem.MHFItemStack var items []mhfitem.MHFItemStack
s.server.db.QueryRow(`SELECT item_box FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow(`SELECT item_box FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&data)
if len(data) > 0 { if len(data) > 0 {
box := byteframe.NewByteFrameFromBytes(data) box := byteframe.NewByteFrameFromBytes(data)
numStacks := box.ReadUint16() numStacks := box.ReadUint16()
@@ -790,14 +810,18 @@ func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {
items := userGetItems(s) items := userGetItems(s)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteBytes(mhfitem.SerializeWarehouseItems(items)) bf.WriteBytes(mhfitem.SerializeWarehouseItems(items))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateUnionItem) pkt := p.(*mhfpacket.MsgMhfUpdateUnionItem)
newStacks := mhfitem.DiffItemStacks(userGetItems(s), pkt.UpdatedItems) newStacks := mhfitem.DiffItemStacks(userGetItems(s), pkt.UpdatedItems)
s.server.db.Exec(`UPDATE users u SET item_box=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, mhfitem.SerializeWarehouseItems(newStacks), s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`UPDATE users u SET item_box=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, mhfitem.SerializeWarehouseItems(newStacks), s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {}
@@ -806,20 +830,24 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCheckWeeklyStamp) pkt := p.(*mhfpacket.MsgMhfCheckWeeklyStamp)
var total, redeemed, updated uint16 var total, redeemed, updated uint16
var lastCheck time.Time var lastCheck time.Time
err := s.server.db.QueryRow(fmt.Sprintf("SELECT %s_checked FROM stamps WHERE character_id=$1", pkt.StampType), s.charID).Scan(&lastCheck) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow(fmt.Sprintf("SELECT %s_checked FROM stamps WHERE character_id=$1", pkt.StampType), s.CharID).Scan(&lastCheck)
if err != nil { if err != nil {
lastCheck = gametime.TimeAdjusted() lastCheck = gametime.TimeAdjusted()
s.server.db.Exec("INSERT INTO stamps (character_id, hl_checked, ex_checked) VALUES ($1, $2, $2)", s.charID, gametime.TimeAdjusted()) database.Exec("INSERT INTO stamps (character_id, hl_checked, ex_checked) VALUES ($1, $2, $2)", s.CharID, gametime.TimeAdjusted())
} else { } else {
s.server.db.Exec(fmt.Sprintf(`UPDATE stamps SET %s_checked=$1 WHERE character_id=$2`, pkt.StampType), gametime.TimeAdjusted(), s.charID) database.Exec(fmt.Sprintf(`UPDATE stamps SET %s_checked=$1 WHERE character_id=$2`, pkt.StampType), gametime.TimeAdjusted(), s.CharID)
} }
if lastCheck.Before(gametime.TimeWeekStart()) { if lastCheck.Before(gametime.TimeWeekStart()) {
s.server.db.Exec(fmt.Sprintf("UPDATE stamps SET %s_total=%s_total+1 WHERE character_id=$1", pkt.StampType, pkt.StampType), s.charID) database.Exec(fmt.Sprintf("UPDATE stamps SET %s_total=%s_total+1 WHERE character_id=$1", pkt.StampType, pkt.StampType), s.CharID)
updated = 1 updated = 1
} }
s.server.db.QueryRow(fmt.Sprintf("SELECT %s_total, %s_redeemed FROM stamps WHERE character_id=$1", pkt.StampType, pkt.StampType), s.charID).Scan(&total, &redeemed) database.QueryRow(fmt.Sprintf("SELECT %s_total, %s_redeemed FROM stamps WHERE character_id=$1", pkt.StampType, pkt.StampType), s.CharID).Scan(&total, &redeemed)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(total) bf.WriteUint16(total)
bf.WriteUint16(redeemed) bf.WriteUint16(redeemed)
@@ -827,18 +855,22 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix())) bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix()))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfExchangeWeeklyStamp) pkt := p.(*mhfpacket.MsgMhfExchangeWeeklyStamp)
var total, redeemed uint16 var total, redeemed uint16
var tktStack mhfitem.MHFItemStack var tktStack mhfitem.MHFItemStack
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.Unk1 == 10 { // Yearly Sub Ex if pkt.Unk1 == 10 { // Yearly Sub Ex
s.server.db.QueryRow("UPDATE stamps SET hl_total=hl_total-48, hl_redeemed=hl_redeemed-48 WHERE character_id=$1 RETURNING hl_total, hl_redeemed", s.charID).Scan(&total, &redeemed) database.QueryRow("UPDATE stamps SET hl_total=hl_total-48, hl_redeemed=hl_redeemed-48 WHERE character_id=$1 RETURNING hl_total, hl_redeemed", s.CharID).Scan(&total, &redeemed)
tktStack = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: 2210}, Quantity: 1} tktStack = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: 2210}, Quantity: 1}
} else { } else {
s.server.db.QueryRow(fmt.Sprintf("UPDATE stamps SET %s_redeemed=%s_redeemed+8 WHERE character_id=$1 RETURNING %s_total, %s_redeemed", pkt.StampType, pkt.StampType, pkt.StampType, pkt.StampType), s.charID).Scan(&total, &redeemed) database.QueryRow(fmt.Sprintf("UPDATE stamps SET %s_redeemed=%s_redeemed+8 WHERE character_id=$1 RETURNING %s_total, %s_redeemed", pkt.StampType, pkt.StampType, pkt.StampType, pkt.StampType), s.CharID).Scan(&total, &redeemed)
if pkt.StampType == "hl" { if pkt.StampType == "hl" {
tktStack = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: 1630}, Quantity: 5} tktStack = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: 1630}, Quantity: 5}
} else { } else {
@@ -853,16 +885,20 @@ func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(tktStack.Item.ItemID) bf.WriteUint16(tktStack.Item.ItemID)
bf.WriteUint16(tktStack.Quantity) bf.WriteUint16(tktStack.Quantity)
bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix())) bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix()))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func getGoocooData(s *Session, cid uint32) [][]byte { func getGoocooData(s *Session, cid uint32) [][]byte {
var goocoo []byte var goocoo []byte
var goocoos [][]byte var goocoos [][]byte
for i := 0; i < 5; i++ { database, err := db.GetDB()
err := s.server.db.QueryRow(fmt.Sprintf("SELECT goocoo%d FROM goocoo WHERE id=$1", i), cid).Scan(&goocoo)
if err != nil { if err != nil {
s.server.db.Exec("INSERT INTO goocoo (id) VALUES ($1)", s.charID) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
for i := 0; i < 5; i++ {
err := database.QueryRow(fmt.Sprintf("SELECT goocoo%d FROM goocoo WHERE id=$1", i), cid).Scan(&goocoo)
if err != nil {
database.Exec("INSERT INTO goocoo (id) VALUES ($1)", s.CharID)
return goocoos return goocoos
} }
if err == nil && goocoo != nil { if err == nil && goocoo != nil {
@@ -875,20 +911,24 @@ func getGoocooData(s *Session, cid uint32) [][]byte {
func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot) pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
goocoos := getGoocooData(s, s.charID) goocoos := getGoocooData(s, s.CharID)
bf.WriteUint16(uint16(len(goocoos))) bf.WriteUint16(uint16(len(goocoos)))
bf.WriteUint16(0) bf.WriteUint16(0)
for _, goocoo := range goocoos { for _, goocoo := range goocoos {
bf.WriteBytes(goocoo) bf.WriteBytes(goocoo)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateGuacot) pkt := p.(*mhfpacket.MsgMhfUpdateGuacot)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
for _, goocoo := range pkt.Goocoos { for _, goocoo := range pkt.Goocoos {
if goocoo.Data1[0] == 0 { if goocoo.Data1[0] == 0 {
s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.charID) database.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.CharID)
} else { } else {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(goocoo.Index) bf.WriteUint32(goocoo.Index)
@@ -900,11 +940,11 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
} }
bf.WriteUint8(uint8(len(goocoo.Name))) bf.WriteUint8(uint8(len(goocoo.Name)))
bf.WriteBytes(goocoo.Name) bf.WriteBytes(goocoo.Name)
s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=$1 WHERE id=$2", goocoo.Index), bf.Data(), s.charID) database.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=$1 WHERE id=$2", goocoo.Index), bf.Data(), s.CharID)
dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", goocoo.Index)) dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", goocoo.Index))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type Scenario struct { type Scenario struct {
@@ -921,11 +961,15 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter) pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter)
var scenarios []Scenario var scenarios []Scenario
var scenario Scenario var scenario Scenario
scenarioData, err := s.server.db.Queryx("SELECT scenario_id, category_id FROM scenario_counter") database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
scenarioData, err := database.Queryx("SELECT scenario_id, category_id FROM scenario_counter")
if err != nil { if err != nil {
scenarioData.Close() scenarioData.Close()
s.logger.Error("Failed to get scenario counter info from db", zap.Error(err)) s.Logger.Error("Failed to get scenario counter info from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for scenarioData.Next() { for scenarioData.Next() {
@@ -954,26 +998,29 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) {
} }
bf.WriteUint8(scenario.CategoryID) bf.WriteUint8(scenario.CategoryID)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetEtcPoints) pkt := p.(*mhfpacket.MsgMhfGetEtcPoints)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var dailyTime time.Time var dailyTime time.Time
_ = s.server.db.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.charID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime) _ = database.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.CharID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime)
if gametime.TimeAdjusted().After(dailyTime) { if gametime.TimeAdjusted().After(dailyTime) {
s.server.db.Exec("UPDATE characters SET bonus_quests = 0, daily_quests = 0 WHERE id=$1", s.charID) database.Exec("UPDATE characters SET bonus_quests = 0, daily_quests = 0 WHERE id=$1", s.CharID)
} }
var bonusQuests, dailyQuests, promoPoints uint32 var bonusQuests, dailyQuests, promoPoints uint32
_ = s.server.db.QueryRow(`SELECT bonus_quests, daily_quests, promo_points FROM characters WHERE id = $1`, s.charID).Scan(&bonusQuests, &dailyQuests, &promoPoints) _ = database.QueryRow(`SELECT bonus_quests, daily_quests, promo_points FROM characters WHERE id = $1`, s.CharID).Scan(&bonusQuests, &dailyQuests, &promoPoints)
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint8(3) // Maybe a count of uint32(s)? resp.WriteUint8(3) // Maybe a count of uint32(s)?
resp.WriteUint32(bonusQuests) resp.WriteUint32(bonusQuests)
resp.WriteUint32(dailyQuests) resp.WriteUint32(dailyQuests)
resp.WriteUint32(promoPoints) resp.WriteUint32(promoPoints)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {
@@ -988,17 +1035,20 @@ func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {
case 2: case 2:
column = "promo_points" column = "promo_points"
} }
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var value int16 var value int16
err := s.server.db.QueryRow(fmt.Sprintf(`SELECT %s FROM characters WHERE id = $1`, column), s.charID).Scan(&value) err = database.QueryRow(fmt.Sprintf(`SELECT %s FROM characters WHERE id = $1`, column), s.CharID).Scan(&value)
if err == nil { if err == nil {
if value+pkt.Delta < 0 { if value+pkt.Delta < 0 {
s.server.db.Exec(fmt.Sprintf(`UPDATE characters SET %s = 0 WHERE id = $1`, column), s.charID) database.Exec(fmt.Sprintf(`UPDATE characters SET %s = 0 WHERE id = $1`, column), s.CharID)
} else { } else {
s.server.db.Exec(fmt.Sprintf(`UPDATE characters SET %s = %s + $1 WHERE id = $2`, column, column), pkt.Delta, s.charID) database.Exec(fmt.Sprintf(`UPDATE characters SET %s = %s + $1 WHERE id = $2`, column, column), pkt.Delta, s.CharID)
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
@@ -1017,7 +1067,7 @@ func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
{300, 5392, 1, 5392, 3}, {300, 5392, 1, 5392, 3},
{999, 5392, 1, 5392, 4}, {999, 5392, 1, 5392, 4},
} }
if _config.ErupeConfig.ClientID <= _config.Z1 { if config.GetConfig().ClientID <= config.Z1 {
for _, reward := range rewards { for _, reward := range rewards {
if pkt.HR >= reward.HR { if pkt.HR >= reward.HR {
pkt.Item1 = reward.Item1 pkt.Item1 = reward.Item1
@@ -1030,12 +1080,16 @@ func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(pkt.HR) bf.WriteUint16(pkt.HR)
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
bf.WriteUint16(pkt.GR) bf.WriteUint16(pkt.GR)
} }
var stamps, rewardTier, rewardUnk uint16 var stamps, rewardTier, rewardUnk uint16
reward := mhfitem.MHFItemStack{Item: mhfitem.MHFItem{}} reward := mhfitem.MHFItemStack{Item: mhfitem.MHFItem{}}
s.server.db.QueryRow(`UPDATE characters SET stampcard = stampcard + $1 WHERE id = $2 RETURNING stampcard`, pkt.Stamps, s.charID).Scan(&stamps) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow(`UPDATE characters SET stampcard = stampcard + $1 WHERE id = $2 RETURNING stampcard`, pkt.Stamps, s.CharID).Scan(&stamps)
bf.WriteUint16(stamps - pkt.Stamps) bf.WriteUint16(stamps - pkt.Stamps)
bf.WriteUint16(stamps) bf.WriteUint16(stamps)
@@ -1055,14 +1109,14 @@ func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(rewardUnk) bf.WriteUint16(rewardUnk)
bf.WriteUint16(reward.Item.ItemID) bf.WriteUint16(reward.Item.ItemID)
bf.WriteUint16(reward.Quantity) bf.WriteUint16(reward.Quantity)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfStampcardPrize(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfStampcardPrize(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfUnreserveSrg(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUnreserveSrg(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUnreserveSrg) pkt := p.(*mhfpacket.MsgMhfUnreserveSrg)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {}
@@ -1072,10 +1126,10 @@ func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix())) // Start bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix())) // Start
bf.WriteUint32(uint32(gametime.TimeWeekNext().Unix())) // End bf.WriteUint32(uint32(gametime.TimeWeekNext().Unix())) // End
bf.WriteInt32(s.server.erupeConfig.EarthStatus) bf.WriteInt32(config.GetConfig().EarthStatus)
bf.WriteInt32(s.server.erupeConfig.EarthID) bf.WriteInt32(config.GetConfig().EarthID)
for i, m := range s.server.erupeConfig.EarthMonsters { for i, m := range config.GetConfig().EarthMonsters {
if _config.ErupeConfig.ClientID <= _config.G9 { if config.GetConfig().ClientID <= config.G9 {
if i == 3 { if i == 3 {
break break
} }
@@ -1085,7 +1139,7 @@ func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
} }
bf.WriteInt32(m) bf.WriteInt32(m)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {}
@@ -1124,7 +1178,7 @@ func handleMsgMhfGetEarthValue(s *Session, p mhfpacket.MHFPacket) {
} }
data = append(data, bf) data = append(data, bf)
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfDebugPostValue(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfDebugPostValue(s *Session, p mhfpacket.MHFPacket) {}
@@ -1135,7 +1189,7 @@ func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {
for i := uint16(0); i < pkt.Results; i++ { for i := uint16(0); i < pkt.Results; i++ {
bf.WriteUint32(0) bf.WriteUint32(0)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {
@@ -1143,7 +1197,7 @@ func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint16(0) bf.WriteUint16(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
type SeibattleTimetable struct { type SeibattleTimetable struct {
@@ -1281,12 +1335,12 @@ func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
data = append(data, bf) data = append(data, bf)
} }
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostSeibattle) pkt := p.(*mhfpacket.MsgMhfPostSeibattle)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {}
@@ -1297,10 +1351,10 @@ func handleMsgMhfSetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {}
func equipSkinHistSize() int { func equipSkinHistSize() int {
size := 3200 size := 3200
if _config.ErupeConfig.ClientID <= _config.Z2 { if config.GetConfig().ClientID <= config.Z2 {
size = 2560 size = 2560
} }
if _config.ErupeConfig.ClientID <= _config.Z1 { if config.GetConfig().ClientID <= config.Z1 {
size = 1280 size = 1280
} }
return size return size
@@ -1310,22 +1364,30 @@ func handleMsgMhfGetEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetEquipSkinHist) pkt := p.(*mhfpacket.MsgMhfGetEquipSkinHist)
size := equipSkinHistSize() size := equipSkinHistSize()
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(skin_hist::bytea, $2::bytea) FROM characters WHERE id = $1", s.charID, make([]byte, size)).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to load skin_hist", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT COALESCE(skin_hist::bytea, $2::bytea) FROM characters WHERE id = $1", s.CharID, make([]byte, size)).Scan(&data)
if err != nil {
s.Logger.Error("Failed to load skin_hist", zap.Error(err))
data = make([]byte, size) data = make([]byte, size)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateEquipSkinHist) pkt := p.(*mhfpacket.MsgMhfUpdateEquipSkinHist)
size := equipSkinHistSize() size := equipSkinHistSize()
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(skin_hist, $2) FROM characters WHERE id = $1", s.charID, make([]byte, size)).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to get skin_hist", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) }
err = database.QueryRow("SELECT COALESCE(skin_hist, $2) FROM characters WHERE id = $1", s.CharID, make([]byte, size)).Scan(&data)
if err != nil {
s.Logger.Error("Failed to get skin_hist", zap.Error(err))
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
@@ -1336,15 +1398,15 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
bitInByte := bit % 8 bitInByte := bit % 8
data[startByte+byteInd] |= bits.Reverse8(1 << uint(bitInByte)) data[startByte+byteInd] |= bits.Reverse8(1 << uint(bitInByte))
dumpSaveData(s, data, "skinhist") dumpSaveData(s, data, "skinhist")
s.server.db.Exec("UPDATE characters SET skin_hist=$1 WHERE id=$2", data, s.charID) database.Exec("UPDATE characters SET skin_hist=$1 WHERE id=$2", data, s.CharID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetUdShopCoin(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdShopCoin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdShopCoin) pkt := p.(*mhfpacket.MsgMhfGetUdShopCoin)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(0) bf.WriteUint32(0)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUseUdShopCoin(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfUseUdShopCoin(s *Session, p mhfpacket.MHFPacket) {}
@@ -1353,22 +1415,30 @@ func handleMsgMhfGetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetEnhancedMinidata) pkt := p.(*mhfpacket.MsgMhfGetEnhancedMinidata)
// this looks to be the detailed chunk of information you can pull up on players in town // this looks to be the detailed chunk of information you can pull up on players in town
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT minidata FROM characters WHERE id = $1", pkt.CharID).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to load minidata") s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT minidata FROM characters WHERE id = $1", pkt.CharID).Scan(&data)
if err != nil {
s.Logger.Error("Failed to load minidata")
data = make([]byte, 1) data = make([]byte, 1)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetEnhancedMinidata) pkt := p.(*mhfpacket.MsgMhfSetEnhancedMinidata)
dumpSaveData(s, pkt.RawDataPayload, "minidata") dumpSaveData(s, pkt.RawDataPayload, "minidata")
_, err := s.server.db.Exec("UPDATE characters SET minidata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to save minidata", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) _, err = database.Exec("UPDATE characters SET minidata=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil {
s.Logger.Error("Failed to save minidata", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) {
@@ -1378,7 +1448,7 @@ func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) {
// It can be worried about later if we ever get to the point where there are // It can be worried about later if we ever get to the point where there are
// full servers to actually need to migrate people from and empty ones to // full servers to actually need to migrate people from and empty ones to
pkt := p.(*mhfpacket.MsgMhfGetLobbyCrowd) pkt := p.(*mhfpacket.MsgMhfGetLobbyCrowd)
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x320)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x320))
} }
type TrendWeapon struct { type TrendWeapon struct {
@@ -1389,8 +1459,12 @@ type TrendWeapon struct {
func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetTrendWeapon) pkt := p.(*mhfpacket.MsgMhfGetTrendWeapon)
trendWeapons := [14][3]TrendWeapon{} trendWeapons := [14][3]TrendWeapon{}
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
for i := uint8(0); i < 14; i++ { for i := uint8(0); i < 14; i++ {
rows, err := s.server.db.Query(`SELECT weapon_id FROM trend_weapons WHERE weapon_type=$1 ORDER BY count DESC LIMIT 3`, i) rows, err := database.Query(`SELECT weapon_id FROM trend_weapons WHERE weapon_type=$1 ORDER BY count DESC LIMIT 3`, i)
if err != nil { if err != nil {
continue continue
} }
@@ -1414,12 +1488,16 @@ func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) {
} }
bf.Seek(0, 0) bf.Seek(0, 0)
bf.WriteUint8(x) bf.WriteUint8(x)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUpdateUseTrendWeaponLog(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateUseTrendWeaponLog(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateUseTrendWeaponLog) pkt := p.(*mhfpacket.MsgMhfUpdateUseTrendWeaponLog)
s.server.db.Exec(`INSERT INTO trend_weapons (weapon_id, weapon_type, count) VALUES ($1, $2, 1) ON CONFLICT (weapon_id) DO database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`INSERT INTO trend_weapons (weapon_id, weapon_type, count) VALUES ($1, $2, 1) ON CONFLICT (weapon_id) DO
UPDATE SET count = trend_weapons.count+1`, pkt.WeaponID, pkt.WeaponType) UPDATE SET count = trend_weapons.count+1`, pkt.WeaponID, pkt.WeaponType)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -3,6 +3,7 @@ package channelserver
import ( import (
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"fmt" "fmt"
"io" "io"
) )
@@ -88,19 +89,23 @@ func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetAchievement) pkt := p.(*mhfpacket.MsgMhfGetAchievement)
var exists int var exists int
err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", pkt.CharID).Scan(&exists) database, err := db.GetDB()
if err != nil { if err != nil {
s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", pkt.CharID) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT id FROM achievements WHERE id=$1", pkt.CharID).Scan(&exists)
if err != nil {
database.Exec("INSERT INTO achievements (id) VALUES ($1)", pkt.CharID)
} }
var scores [33]int32 var scores [33]int32
err = s.server.db.QueryRow("SELECT * FROM achievements WHERE id=$1", pkt.CharID).Scan(&scores[0], err = database.QueryRow("SELECT * FROM achievements WHERE id=$1", pkt.CharID).Scan(&scores[0],
&scores[0], &scores[1], &scores[2], &scores[3], &scores[4], &scores[5], &scores[6], &scores[7], &scores[8], &scores[0], &scores[1], &scores[2], &scores[3], &scores[4], &scores[5], &scores[6], &scores[7], &scores[8],
&scores[9], &scores[10], &scores[11], &scores[12], &scores[13], &scores[14], &scores[15], &scores[16], &scores[9], &scores[10], &scores[11], &scores[12], &scores[13], &scores[14], &scores[15], &scores[16],
&scores[17], &scores[18], &scores[19], &scores[20], &scores[21], &scores[22], &scores[23], &scores[24], &scores[17], &scores[18], &scores[19], &scores[20], &scores[21], &scores[22], &scores[23], &scores[24],
&scores[25], &scores[26], &scores[27], &scores[28], &scores[29], &scores[30], &scores[31], &scores[32]) &scores[25], &scores[26], &scores[27], &scores[28], &scores[29], &scores[30], &scores[31], &scores[32])
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 20)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 20))
return return
} }
@@ -136,26 +141,29 @@ func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint32(points) resp.WriteUint32(points)
resp.WriteUint32(points) resp.WriteUint32(points)
resp.WriteUint32(points) resp.WriteUint32(points)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfSetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetCaAchievementHist) pkt := p.(*mhfpacket.MsgMhfSetCaAchievementHist)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfResetAchievement(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfResetAchievement(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAddAchievement) pkt := p.(*mhfpacket.MsgMhfAddAchievement)
database, err := db.GetDB()
var exists int
err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", s.charID).Scan(&exists)
if err != nil { if err != nil {
s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", s.charID) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var exists int
err = database.QueryRow("SELECT id FROM achievements WHERE id=$1", s.CharID).Scan(&exists)
if err != nil {
database.Exec("INSERT INTO achievements (id) VALUES ($1)", s.CharID)
} }
s.server.db.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", pkt.AchievementID, pkt.AchievementID), s.charID) database.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", pkt.AchievementID, pkt.AchievementID), s.CharID)
} }
func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -1,6 +1,7 @@
package channelserver package channelserver
import ( import (
"erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
@@ -18,7 +19,7 @@ func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(0) bf.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
// Checks the status of Bultin Board Server to see if authenticated // Checks the status of Bultin Board Server to see if authenticated
@@ -29,7 +30,7 @@ func handleMsgMhfGetBbsSnsStatus(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(401) //unk http status? bf.WriteUint32(401) //unk http status?
bf.WriteUint32(401) //unk http status? bf.WriteUint32(401) //unk http status?
bf.WriteUint32(0) bf.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
// Tells the game client what host port and gives the bultin board article a token // Tells the game client what host port and gives the bultin board article a token
@@ -39,15 +40,15 @@ func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {
articleToken := token.Generate(40) articleToken := token.Generate(40)
bf.WriteUint32(200) //http status //200 success //4XX An error occured server side bf.WriteUint32(200) //http status //200 success //4XX An error occured server side
bf.WriteUint32(s.server.erupeConfig.Screenshots.Port) bf.WriteUint32(config.GetConfig().Screenshots.Port)
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteBytes(stringsupport.PaddedString(articleToken, 64, false)) bf.WriteBytes(stringsupport.PaddedString(articleToken, 64, false))
bf.WriteBytes(stringsupport.PaddedString(s.server.erupeConfig.Screenshots.Host, 64, false)) bf.WriteBytes(stringsupport.PaddedString(config.GetConfig().Screenshots.Host, 64, false))
//pkt.unk1[3] == Changes sometimes? //pkt.unk1[3] == Changes sometimes?
if s.server.erupeConfig.Screenshots.Enabled && s.server.erupeConfig.Discord.Enabled { if config.GetConfig().Screenshots.Enabled && config.GetConfig().Discord.Enabled {
s.server.DiscordScreenShotSend(pkt.Name, pkt.Title, pkt.Description, articleToken) s.Server.DiscordScreenShotSend(pkt.Name, pkt.Title, pkt.Description, articleToken)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -2,10 +2,11 @@ package channelserver
import ( import (
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/mhfcourse" "erupe-ce/utils/mhfcourse"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"fmt" "fmt"
@@ -18,25 +19,33 @@ import (
func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireCafeItem) pkt := p.(*mhfpacket.MsgMhfAcquireCafeItem)
var netcafePoints uint32 var netcafePoints uint32
err := s.server.db.QueryRow("UPDATE characters SET netcafe_points = netcafe_points - $1 WHERE id = $2 RETURNING netcafe_points", pkt.PointCost, s.charID).Scan(&netcafePoints) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to get netcafe points from db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("UPDATE characters SET netcafe_points = netcafe_points - $1 WHERE id = $2 RETURNING netcafe_points", pkt.PointCost, s.CharID).Scan(&netcafePoints)
if err != nil {
s.Logger.Error("Failed to get netcafe points from db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(netcafePoints) resp.WriteUint32(netcafePoints)
doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateCafepoint) pkt := p.(*mhfpacket.MsgMhfUpdateCafepoint)
var netcafePoints uint32 var netcafePoints uint32
err := s.server.db.QueryRow("SELECT COALESCE(netcafe_points, 0) FROM characters WHERE id = $1", s.charID).Scan(&netcafePoints) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to get netcate points from db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT COALESCE(netcafe_points, 0) FROM characters WHERE id = $1", s.CharID).Scan(&netcafePoints)
if err != nil {
s.Logger.Error("Failed to get netcate points from db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(netcafePoints) resp.WriteUint32(netcafePoints)
doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
@@ -49,9 +58,13 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
// get time after which daily claiming would be valid from db // get time after which daily claiming would be valid from db
var dailyTime time.Time var dailyTime time.Time
err := s.server.db.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.charID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to get daily_time savedata from db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.CharID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime)
if err != nil {
s.Logger.Error("Failed to get daily_time savedata from db", zap.Error(err))
} }
var bondBonus, bonusQuests, dailyQuests uint32 var bondBonus, bonusQuests, dailyQuests uint32
@@ -59,9 +72,9 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
if midday.After(dailyTime) { if midday.After(dailyTime) {
addPointNetcafe(s, 5) addPointNetcafe(s, 5)
bondBonus = 5 // Bond point bonus quests bondBonus = 5 // Bond point bonus quests
bonusQuests = s.server.erupeConfig.GameplayOptions.BonusQuestAllowance bonusQuests = config.GetConfig().GameplayOptions.BonusQuestAllowance
dailyQuests = s.server.erupeConfig.GameplayOptions.DailyQuestAllowance dailyQuests = config.GetConfig().GameplayOptions.DailyQuestAllowance
s.server.db.Exec("UPDATE characters SET daily_time=$1, bonus_quests = $2, daily_quests = $3 WHERE id=$4", midday, bonusQuests, dailyQuests, s.charID) database.Exec("UPDATE characters SET daily_time=$1, bonus_quests = $2, daily_quests = $3 WHERE id=$4", midday, bonusQuests, dailyQuests, s.CharID)
bf.WriteBool(true) // Success? bf.WriteBool(true) // Success?
} else { } else {
bf.WriteBool(false) bf.WriteBool(false)
@@ -69,27 +82,30 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(bondBonus) bf.WriteUint32(bondBonus)
bf.WriteUint32(bonusQuests) bf.WriteUint32(bonusQuests)
bf.WriteUint32(dailyQuests) bf.WriteUint32(dailyQuests)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetCafeDuration) pkt := p.(*mhfpacket.MsgMhfGetCafeDuration)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var cafeReset time.Time var cafeReset time.Time
err := s.server.db.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.charID).Scan(&cafeReset) err = database.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.CharID).Scan(&cafeReset)
if err != nil { if err != nil {
cafeReset = gametime.TimeWeekNext() cafeReset = gametime.TimeWeekNext()
s.server.db.Exec(`UPDATE characters SET cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID) database.Exec(`UPDATE characters SET cafe_reset=$1 WHERE id=$2`, cafeReset, s.CharID)
} }
if gametime.TimeAdjusted().After(cafeReset) { if gametime.TimeAdjusted().After(cafeReset) {
cafeReset = gametime.TimeWeekNext() cafeReset = gametime.TimeWeekNext()
s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID) database.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2`, cafeReset, s.CharID)
s.server.db.Exec(`DELETE FROM cafe_accepted WHERE character_id=$1`, s.charID) database.Exec(`DELETE FROM cafe_accepted WHERE character_id=$1`, s.CharID)
} }
var cafeTime uint32 var cafeTime uint32
err = s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime) err = database.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.CharID).Scan(&cafeTime)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -97,11 +113,11 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
cafeTime = uint32(gametime.TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime cafeTime = uint32(gametime.TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime
} }
bf.WriteUint32(cafeTime) bf.WriteUint32(cafeTime)
if _config.ErupeConfig.ClientID >= _config.ZZ { if config.GetConfig().ClientID >= config.ZZ {
bf.WriteUint16(0) bf.WriteUint16(0)
ps.Uint16(bf, fmt.Sprintf(s.server.i18n.cafe.reset, int(cafeReset.Month()), cafeReset.Day()), true) ps.Uint16(bf, fmt.Sprintf(s.Server.i18n.cafe.reset, int(cafeReset.Month()), cafeReset.Day()), true)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
type CafeBonus struct { type CafeBonus struct {
@@ -116,26 +132,29 @@ type CafeBonus struct {
func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetCafeDurationBonusInfo) pkt := p.(*mhfpacket.MsgMhfGetCafeDurationBonusInfo)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var count uint32 var count uint32
rows, err := s.server.db.Queryx(` rows, err := database.Queryx(`
SELECT cb.id, time_req, item_type, item_id, quantity, SELECT cb.id, time_req, item_type, item_id, quantity,
( (
SELECT count(*) SELECT count(*)
FROM cafe_accepted ca FROM cafe_accepted ca
WHERE cb.id = ca.cafe_id AND ca.character_id = $1 WHERE cb.id = ca.cafe_id AND ca.character_id = $1
)::int::bool AS claimed )::int::bool AS claimed
FROM cafebonus cb ORDER BY id ASC;`, s.charID) FROM cafebonus cb ORDER BY id ASC;`, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Error getting cafebonus", zap.Error(err)) s.Logger.Error("Error getting cafebonus", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
for rows.Next() { for rows.Next() {
count++ count++
cafeBonus := &CafeBonus{} cafeBonus := &CafeBonus{}
err = rows.StructScan(&cafeBonus) err = rows.StructScan(&cafeBonus)
if err != nil { if err != nil {
s.logger.Error("Error scanning cafebonus", zap.Error(err)) s.Logger.Error("Error scanning cafebonus", zap.Error(err))
} }
bf.WriteUint32(cafeBonus.TimeReq) bf.WriteUint32(cafeBonus.TimeReq)
bf.WriteUint32(cafeBonus.ItemType) bf.WriteUint32(cafeBonus.ItemType)
@@ -148,7 +167,7 @@ func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) resp.WriteUint32(uint32(gametime.TimeAdjusted().Unix()))
resp.WriteUint32(count) resp.WriteUint32(count)
resp.WriteBytes(bf.Data()) resp.WriteBytes(bf.Data())
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
} }
@@ -157,7 +176,11 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var count uint32 var count uint32
bf.WriteUint32(0) bf.WriteUint32(0)
rows, err := s.server.db.Queryx(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`
SELECT c.id, time_req, item_type, item_id, quantity SELECT c.id, time_req, item_type, item_id, quantity
FROM cafebonus c FROM cafebonus c
WHERE ( WHERE (
@@ -168,9 +191,9 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {
SELECT ch.cafe_time + $2 SELECT ch.cafe_time + $2
FROM characters ch FROM characters ch
WHERE ch.id = $1 WHERE ch.id = $1
) >= time_req`, s.charID, gametime.TimeAdjusted().Unix()-s.sessionStart) ) >= time_req`, s.CharID, gametime.TimeAdjusted().Unix()-s.sessionStart)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
for rows.Next() { for rows.Next() {
cafeBonus := &CafeBonus{} cafeBonus := &CafeBonus{}
@@ -186,15 +209,19 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {
} }
bf.Seek(0, io.SeekStart) bf.Seek(0, io.SeekStart)
bf.WriteUint32(count) bf.WriteUint32(count)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
} }
func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostCafeDurationBonusReceived) pkt := p.(*mhfpacket.MsgMhfPostCafeDurationBonusReceived)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var cafeBonus CafeBonus var cafeBonus CafeBonus
for _, cbID := range pkt.CafeBonusID { for _, cbID := range pkt.CafeBonusID {
err := s.server.db.QueryRow(` err := database.QueryRow(`
SELECT cb.id, item_type, quantity FROM cafebonus cb WHERE cb.id=$1 SELECT cb.id, item_type, quantity FROM cafebonus cb WHERE cb.id=$1
`, cbID).Scan(&cafeBonus.ID, &cafeBonus.ItemType, &cafeBonus.Quantity) `, cbID).Scan(&cafeBonus.ID, &cafeBonus.ItemType, &cafeBonus.Quantity)
if err == nil { if err == nil {
@@ -202,85 +229,101 @@ func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket
addPointNetcafe(s, int(cafeBonus.Quantity)) addPointNetcafe(s, int(cafeBonus.Quantity))
} }
} }
s.server.db.Exec("INSERT INTO public.cafe_accepted VALUES ($1, $2)", cbID, s.charID) database.Exec("INSERT INTO public.cafe_accepted VALUES ($1, $2)", cbID, s.CharID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func addPointNetcafe(s *Session, p int) error { func addPointNetcafe(s *Session, p int) error {
var points int var points int
err := s.server.db.QueryRow("SELECT netcafe_points FROM characters WHERE id = $1", s.charID).Scan(&points) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT netcafe_points FROM characters WHERE id = $1", s.CharID).Scan(&points)
if err != nil { if err != nil {
return err return err
} }
if points+p > s.server.erupeConfig.GameplayOptions.MaximumNP { if points+p > config.GetConfig().GameplayOptions.MaximumNP {
points = s.server.erupeConfig.GameplayOptions.MaximumNP points = config.GetConfig().GameplayOptions.MaximumNP
} else { } else {
points += p points += p
} }
s.server.db.Exec("UPDATE characters SET netcafe_points=$1 WHERE id=$2", points, s.charID) database.Exec("UPDATE characters SET netcafe_points=$1 WHERE id=$2", points, s.CharID)
return nil return nil
} }
func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfStartBoostTime) pkt := p.(*mhfpacket.MsgMhfStartBoostTime)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
boostLimit := gametime.TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.BoostTimeDuration) * time.Second) database, err := db.GetDB()
if s.server.erupeConfig.GameplayOptions.DisableBoostTime { if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
boostLimit := gametime.TimeAdjusted().Add(time.Duration(config.GetConfig().GameplayOptions.BoostTimeDuration) * time.Second)
if config.GetConfig().GameplayOptions.DisableBoostTime {
bf.WriteUint32(0) bf.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
return return
} }
s.server.db.Exec("UPDATE characters SET boost_time=$1 WHERE id=$2", boostLimit, s.charID) database.Exec("UPDATE characters SET boost_time=$1 WHERE id=$2", boostLimit, s.CharID)
bf.WriteUint32(uint32(boostLimit.Unix())) bf.WriteUint32(uint32(boostLimit.Unix()))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetBoostTime(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetBoostTime(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetBoostTime) pkt := p.(*mhfpacket.MsgMhfGetBoostTime)
doAckBufSucceed(s, pkt.AckHandle, []byte{}) DoAckBufSucceed(s, pkt.AckHandle, []byte{})
} }
func handleMsgMhfGetBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetBoostTimeLimit) pkt := p.(*mhfpacket.MsgMhfGetBoostTimeLimit)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var boostLimit time.Time var boostLimit time.Time
err := s.server.db.QueryRow("SELECT boost_time FROM characters WHERE id=$1", s.charID).Scan(&boostLimit) err = database.QueryRow("SELECT boost_time FROM characters WHERE id=$1", s.CharID).Scan(&boostLimit)
if err != nil { if err != nil {
bf.WriteUint32(0) bf.WriteUint32(0)
} else { } else {
bf.WriteUint32(uint32(boostLimit.Unix())) bf.WriteUint32(uint32(boostLimit.Unix()))
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetBoostRight(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetBoostRight(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetBoostRight) pkt := p.(*mhfpacket.MsgMhfGetBoostRight)
var boostLimit time.Time var boostLimit time.Time
err := s.server.db.QueryRow("SELECT boost_time FROM characters WHERE id=$1", s.charID).Scan(&boostLimit) database, err := db.GetDB()
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT boost_time FROM characters WHERE id=$1", s.CharID).Scan(&boostLimit)
if err != nil {
DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
if boostLimit.After(gametime.TimeAdjusted()) { if boostLimit.After(gametime.TimeAdjusted()) {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x02}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x02})
} }
} }
func handleMsgMhfPostBoostTimeQuestReturn(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostBoostTimeQuestReturn(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostBoostTimeQuestReturn) pkt := p.(*mhfpacket.MsgMhfPostBoostTimeQuestReturn)
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) pkt := p.(*mhfpacket.MsgMhfPostBoostTime)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) 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) pkt := p.(*mhfpacket.MsgMhfPostBoostTimeLimit)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -1,7 +1,7 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
@@ -68,7 +68,7 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt16(event.MaxHR) bf.WriteInt16(event.MaxHR)
bf.WriteInt16(event.MinSR) bf.WriteInt16(event.MinSR)
bf.WriteInt16(event.MaxSR) bf.WriteInt16(event.MaxSR)
if _config.ErupeConfig.ClientID >= _config.G3 { if config.GetConfig().ClientID >= config.G3 {
bf.WriteInt16(event.MinGR) bf.WriteInt16(event.MinGR)
bf.WriteInt16(event.MaxGR) bf.WriteInt16(event.MaxGR)
} }
@@ -129,7 +129,7 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(link.CategoryID) bf.WriteUint16(link.CategoryID)
bf.WriteUint32(link.CampaignID) bf.WriteUint32(link.CampaignID)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {
@@ -137,14 +137,14 @@ func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(1) bf.WriteUint16(1)
bf.WriteUint16(0) bf.WriteUint16(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) 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)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(1) bf.WriteUint32(1)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {
@@ -167,10 +167,10 @@ func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(item.Unk4) bf.WriteUint32(item.Unk4)
bf.WriteUint32(item.Unk5) bf.WriteUint32(item.Unk5)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireItem) pkt := p.(*mhfpacket.MsgMhfAcquireItem)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -67,7 +67,7 @@ func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {
data = append(data, bf) data = append(data, bf)
} }
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {}
@@ -75,12 +75,12 @@ func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetTinyBin) pkt := p.(*mhfpacket.MsgMhfGetTinyBin)
// requested after conquest quests // requested after conquest quests
doAckBufSucceed(s, pkt.AckHandle, []byte{}) DoAckBufSucceed(s, pkt.AckHandle, []byte{})
} }
func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostTinyBin) pkt := p.(*mhfpacket.MsgMhfPostTinyBin)
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) {
@@ -92,7 +92,7 @@ func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
*/ */
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {
@@ -108,7 +108,7 @@ func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(1) bf.WriteInt32(1)
bf.WriteBytes(stringsupport.PaddedString("Test", 14, true)) bf.WriteBytes(stringsupport.PaddedString("Test", 14, true))
*/ */
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) {
@@ -119,5 +119,5 @@ func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
*/ */
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }

View File

@@ -3,10 +3,11 @@ package channelserver
import ( import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/binpacket" "erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"erupe-ce/utils/mhfcid" "erupe-ce/utils/mhfcid"
"erupe-ce/utils/mhfcourse" "erupe-ce/utils/mhfcourse"
@@ -43,17 +44,17 @@ const (
) )
var ( var (
commands map[string]_config.Command commands map[string]config.Command
once sync.Once // Ensures that initialization happens only once once sync.Once // Ensures that initialization happens only once
commandsMu sync.Mutex // Mutex to ensure thread safety for commands map commandsMu sync.Mutex // Mutex to ensure thread safety for commands map
) )
func (server *Server) initCommands() { func (server *ChannelServer) initCommands() {
once.Do(func() { once.Do(func() {
commands = make(map[string]_config.Command) commands = make(map[string]config.Command)
commandLogger := logger.Get().Named("command") commandLogger := logger.Get().Named("command")
cmds := _config.ErupeConfig.Commands cmds := config.GetConfig().Commands
for _, cmd := range cmds { for _, cmd := range cmds {
commands[cmd.Name] = cmd commands[cmd.Name] = cmd
if cmd.Enabled { if cmd.Enabled {
@@ -65,8 +66,8 @@ func (server *Server) initCommands() {
}) })
} }
func sendDisabledCommandMessage(s *Session, cmd _config.Command) { func sendDisabledCommandMessage(s *Session, cmd config.Command) {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.disabled, cmd.Name)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.disabled, cmd.Name))
} }
func sendServerChatMessage(s *Session, message string) { func sendServerChatMessage(s *Session, message string) {
@@ -92,7 +93,11 @@ func sendServerChatMessage(s *Session, message string) {
} }
func parseChatCommand(s *Session, command string) { func parseChatCommand(s *Session, command string) {
args := strings.Split(command[len(s.server.erupeConfig.CommandPrefix):], " ") database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
args := strings.Split(command[len(config.GetConfig().CommandPrefix):], " ")
switch args[0] { switch args[0] {
case commands["Ban"].Prefix: case commands["Ban"].Prefix:
if s.isOp() { if s.isOp() {
@@ -118,7 +123,7 @@ func parseChatCommand(s *Session, command string) {
expiry = time.Now().Add(time.Duration(length) * time.Hour * 24 * 365) expiry = time.Now().Add(time.Duration(length) * time.Hour * 24 * 365)
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ban.error) sendServerChatMessage(s, s.Server.i18n.commands.ban.error)
return return
} }
} }
@@ -126,39 +131,39 @@ func parseChatCommand(s *Session, command string) {
if cid > 0 { if cid > 0 {
var uid uint32 var uid uint32
var uname string var uname string
err := s.server.db.QueryRow(`SELECT id, username FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, cid).Scan(&uid, &uname) err := database.QueryRow(`SELECT id, username FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, cid).Scan(&uid, &uname)
if err == nil { if err == nil {
if expiry.IsZero() { if expiry.IsZero() {
s.server.db.Exec(`INSERT INTO bans VALUES ($1) database.Exec(`INSERT INTO bans VALUES ($1)
ON CONFLICT (user_id) DO UPDATE SET expires=NULL`, uid) ON CONFLICT (user_id) DO UPDATE SET expires=NULL`, uid)
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.ban.success, uname)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.ban.success, uname))
} else { } else {
s.server.db.Exec(`INSERT INTO bans VALUES ($1, $2) database.Exec(`INSERT INTO bans VALUES ($1, $2)
ON CONFLICT (user_id) DO UPDATE SET expires=$2`, uid, expiry) ON CONFLICT (user_id) DO UPDATE SET expires=$2`, uid, expiry)
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.ban.success, uname)+fmt.Sprintf(s.server.i18n.commands.ban.length, expiry.Format(time.DateTime))) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.ban.success, uname)+fmt.Sprintf(s.Server.i18n.commands.ban.length, expiry.Format(time.DateTime)))
} }
s.server.DisconnectUser(uid) s.Server.DisconnectUser(uid)
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ban.noUser) sendServerChatMessage(s, s.Server.i18n.commands.ban.noUser)
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ban.invalid) sendServerChatMessage(s, s.Server.i18n.commands.ban.invalid)
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ban.error) sendServerChatMessage(s, s.Server.i18n.commands.ban.error)
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.noOp) sendServerChatMessage(s, s.Server.i18n.commands.noOp)
} }
case commands["Timer"].Prefix: case commands["Timer"].Prefix:
if commands["Timer"].Enabled || s.isOp() { if commands["Timer"].Enabled || s.isOp() {
var state bool var state bool
s.server.db.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&state) database.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&state)
s.server.db.Exec(`UPDATE users u SET timer=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, !state, s.charID) database.Exec(`UPDATE users u SET timer=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, !state, s.CharID)
if state { if state {
sendServerChatMessage(s, s.server.i18n.commands.timer.disabled) sendServerChatMessage(s, s.Server.i18n.commands.timer.disabled)
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.timer.enabled) sendServerChatMessage(s, s.Server.i18n.commands.timer.enabled)
} }
} else { } else {
sendDisabledCommandMessage(s, commands["Timer"]) sendDisabledCommandMessage(s, commands["Timer"])
@@ -167,56 +172,56 @@ func parseChatCommand(s *Session, command string) {
if commands["PSN"].Enabled || s.isOp() { if commands["PSN"].Enabled || s.isOp() {
if len(args) > 1 { if len(args) > 1 {
var exists int var exists int
s.server.db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, args[1]).Scan(&exists) database.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, args[1]).Scan(&exists)
if exists == 0 { if exists == 0 {
_, err := s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, args[1], s.charID) _, err := database.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, args[1], s.CharID)
if err == nil { if err == nil {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.psn.success, args[1])) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.psn.success, args[1]))
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.psn.exists) sendServerChatMessage(s, s.Server.i18n.commands.psn.exists)
} }
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.psn.error, commands["PSN"].Prefix)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.psn.error, commands["PSN"].Prefix))
} }
} else { } else {
sendDisabledCommandMessage(s, commands["PSN"]) sendDisabledCommandMessage(s, commands["PSN"])
} }
case commands["Reload"].Prefix: case commands["Reload"].Prefix:
if commands["Reload"].Enabled || s.isOp() { if commands["Reload"].Enabled || s.isOp() {
sendServerChatMessage(s, s.server.i18n.commands.reload) sendServerChatMessage(s, s.Server.i18n.commands.reload)
var temp mhfpacket.MHFPacket var temp mhfpacket.MHFPacket
for _, object := range s.stage.objects { for _, object := range s.stage.objects {
if object.ownerCharID == s.charID { if object.ownerCharID == s.CharID {
continue continue
} }
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id} temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
s.QueueSendMHF(temp) s.QueueSendMHF(temp)
} }
for _, session := range s.server.sessions { for _, session := range s.Server.sessions {
if s == session { if s == session {
continue continue
} }
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID} temp = &mhfpacket.MsgSysDeleteUser{CharID: session.CharID}
s.QueueSendMHF(temp) s.QueueSendMHF(temp)
} }
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
for _, session := range s.server.sessions { for _, session := range s.Server.sessions {
if s == session { if s == session {
continue continue
} }
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} temp = &mhfpacket.MsgSysInsertUser{CharID: session.CharID}
s.QueueSendMHF(temp) s.QueueSendMHF(temp)
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{ temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID, CharID: session.CharID,
BinaryType: uint8(i + 1), BinaryType: uint8(i + 1),
} }
s.QueueSendMHF(temp) s.QueueSendMHF(temp)
} }
} }
for _, obj := range s.stage.objects { for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID { if obj.ownerCharID == s.CharID {
continue continue
} }
temp = &mhfpacket.MsgSysDuplicateObject{ temp = &mhfpacket.MsgSysDuplicateObject{
@@ -234,20 +239,20 @@ func parseChatCommand(s *Session, command string) {
} }
case commands["KeyQuest"].Prefix: case commands["KeyQuest"].Prefix:
if commands["KeyQuest"].Enabled || s.isOp() { if commands["KeyQuest"].Enabled || s.isOp() {
if s.server.erupeConfig.ClientID < _config.G10 { if config.GetConfig().ClientID < config.G10 {
sendServerChatMessage(s, s.server.i18n.commands.kqf.version) sendServerChatMessage(s, s.Server.i18n.commands.kqf.version)
} else { } else {
if len(args) > 1 { if len(args) > 1 {
if args[1] == "get" { if args[1] == "get" {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.kqf.get, s.kqf)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.kqf.get, s.kqf))
} else if args[1] == "set" { } else if args[1] == "set" {
if len(args) > 2 && len(args[2]) == 16 { if len(args) > 2 && len(args[2]) == 16 {
hexd, _ := hex.DecodeString(args[2]) hexd, _ := hex.DecodeString(args[2])
s.kqf = hexd s.kqf = hexd
s.kqfOverride = true s.kqfOverride = true
sendServerChatMessage(s, s.server.i18n.commands.kqf.set.success) sendServerChatMessage(s, s.Server.i18n.commands.kqf.set.success)
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.kqf.set.error, commands["KeyQuest"].Prefix)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.kqf.set.error, commands["KeyQuest"].Prefix))
} }
} }
} }
@@ -259,14 +264,14 @@ func parseChatCommand(s *Session, command string) {
if commands["Rights"].Enabled || s.isOp() { if commands["Rights"].Enabled || s.isOp() {
if len(args) > 1 { if len(args) > 1 {
v, _ := strconv.Atoi(args[1]) v, _ := strconv.Atoi(args[1])
_, err := s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID) _, err := database.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.CharID)
if err == nil { if err == nil {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.rights.success, v)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.rights.success, v))
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.rights.error, commands["Rights"].Prefix)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.rights.error, commands["Rights"].Prefix))
} }
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.rights.error, commands["Rights"].Prefix)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.rights.error, commands["Rights"].Prefix))
} }
} else { } else {
sendDisabledCommandMessage(s, commands["Rights"]) sendDisabledCommandMessage(s, commands["Rights"])
@@ -277,7 +282,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(args[1]) == strings.ToLower(alias) { if strings.ToLower(args[1]) == strings.ToLower(alias) {
if slices.Contains(s.server.erupeConfig.Courses, _config.Course{Name: course.Aliases()[0], Enabled: true}) { if slices.Contains(config.GetConfig().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 {
@@ -290,26 +295,26 @@ func parseChatCommand(s *Session, command string) {
}) })
if ei != -1 { if ei != -1 {
delta = uint32(-1 * math.Pow(2, float64(course.ID))) delta = uint32(-1 * math.Pow(2, float64(course.ID)))
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.course.disabled, course.Aliases()[0])) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.disabled, course.Aliases()[0]))
} }
} else { } else {
delta = uint32(math.Pow(2, float64(course.ID))) delta = uint32(math.Pow(2, float64(course.ID)))
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.course.enabled, course.Aliases()[0])) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.enabled, course.Aliases()[0]))
} }
err := s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt) err := database.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.CharID).Scan(&rightsInt)
if err == nil { if err == nil {
s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.charID) database.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.CharID)
} }
updateRights(s) updateRights(s)
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.course.locked, course.Aliases()[0])) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.locked, course.Aliases()[0]))
} }
return return
} }
} }
} }
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.course.error, commands["Course"].Prefix)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.error, commands["Course"].Prefix))
} }
} else { } else {
sendDisabledCommandMessage(s, commands["Course"]) sendDisabledCommandMessage(s, commands["Course"])
@@ -317,50 +322,50 @@ func parseChatCommand(s *Session, command string) {
case commands["Raviente"].Prefix: case commands["Raviente"].Prefix:
if commands["Raviente"].Enabled || s.isOp() { if commands["Raviente"].Enabled || s.isOp() {
if len(args) > 1 { if len(args) > 1 {
if s.server.getRaviSemaphore() != nil { if s.Server.getRaviSemaphore() != nil {
switch args[1] { switch args[1] {
case "start": case "start":
if s.server.raviente.register[1] == 0 { if s.Server.raviente.register[1] == 0 {
s.server.raviente.register[1] = s.server.raviente.register[3] s.Server.raviente.register[1] = s.Server.raviente.register[3]
sendServerChatMessage(s, s.server.i18n.commands.ravi.start.success) sendServerChatMessage(s, s.Server.i18n.commands.ravi.start.success)
s.notifyRavi() s.notifyRavi()
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ravi.start.error) sendServerChatMessage(s, s.Server.i18n.commands.ravi.start.error)
} }
case "cm", "check", "checkmultiplier", "multiplier": case "cm", "check", "checkmultiplier", "multiplier":
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.ravi.multiplier, s.server.GetRaviMultiplier())) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.ravi.multiplier, s.Server.GetRaviMultiplier()))
case "sr", "sendres", "resurrection", "ss", "sendsed", "rs", "reqsed": case "sr", "sendres", "resurrection", "ss", "sendsed", "rs", "reqsed":
if s.server.erupeConfig.ClientID == _config.ZZ { if config.GetConfig().ClientID == config.ZZ {
switch args[1] { switch args[1] {
case "sr", "sendres", "resurrection": case "sr", "sendres", "resurrection":
if s.server.raviente.state[28] > 0 { if s.Server.raviente.state[28] > 0 {
sendServerChatMessage(s, s.server.i18n.commands.ravi.res.success) sendServerChatMessage(s, s.Server.i18n.commands.ravi.res.success)
s.server.raviente.state[28] = 0 s.Server.raviente.state[28] = 0
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ravi.res.error) sendServerChatMessage(s, s.Server.i18n.commands.ravi.res.error)
} }
case "ss", "sendsed": case "ss", "sendsed":
sendServerChatMessage(s, s.server.i18n.commands.ravi.sed.success) sendServerChatMessage(s, s.Server.i18n.commands.ravi.sed.success)
// Total BerRavi HP // Total BerRavi HP
HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] HP := s.Server.raviente.state[0] + s.Server.raviente.state[1] + s.Server.raviente.state[2] + s.Server.raviente.state[3] + s.Server.raviente.state[4]
s.server.raviente.support[1] = HP s.Server.raviente.support[1] = HP
case "rs", "reqsed": case "rs", "reqsed":
sendServerChatMessage(s, s.server.i18n.commands.ravi.request) sendServerChatMessage(s, s.Server.i18n.commands.ravi.request)
// Total BerRavi HP // Total BerRavi HP
HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] HP := s.Server.raviente.state[0] + s.Server.raviente.state[1] + s.Server.raviente.state[2] + s.Server.raviente.state[3] + s.Server.raviente.state[4]
s.server.raviente.support[1] = HP + 1 s.Server.raviente.support[1] = HP + 1
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ravi.version) sendServerChatMessage(s, s.Server.i18n.commands.ravi.version)
} }
default: default:
sendServerChatMessage(s, s.server.i18n.commands.ravi.error) sendServerChatMessage(s, s.Server.i18n.commands.ravi.error)
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ravi.noPlayers) sendServerChatMessage(s, s.Server.i18n.commands.ravi.noPlayers)
} }
} else { } else {
sendServerChatMessage(s, s.server.i18n.commands.ravi.error) sendServerChatMessage(s, s.Server.i18n.commands.ravi.error)
} }
} else { } else {
sendDisabledCommandMessage(s, commands["Raviente"]) sendDisabledCommandMessage(s, commands["Raviente"])
@@ -377,13 +382,13 @@ func parseChatCommand(s *Session, command string) {
payload.WriteInt16(int16(y)) // Y payload.WriteInt16(int16(y)) // Y
payloadBytes := payload.Data() payloadBytes := payload.Data()
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{ s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID, CharID: s.CharID,
MessageType: BinaryMessageTypeState, MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes, RawDataPayload: payloadBytes,
}) })
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.teleport.success, x, y)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.teleport.success, x, y))
} else { } else {
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.teleport.error, commands["Teleport"].Prefix)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.teleport.error, commands["Teleport"].Prefix))
} }
} else { } else {
sendDisabledCommandMessage(s, commands["Teleport"]) sendDisabledCommandMessage(s, commands["Teleport"])
@@ -391,14 +396,14 @@ func parseChatCommand(s *Session, command string) {
case commands["Discord"].Prefix: case commands["Discord"].Prefix:
if commands["Discord"].Enabled || s.isOp() { if commands["Discord"].Enabled || s.isOp() {
var _token string var _token string
err := s.server.db.QueryRow(`SELECT discord_token FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&_token) err := database.QueryRow(`SELECT discord_token FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&_token)
if err != nil { if err != nil {
randToken := make([]byte, 4) randToken := make([]byte, 4)
rand.Read(randToken) rand.Read(randToken)
_token = fmt.Sprintf("%x-%x", randToken[:2], randToken[2:]) _token = fmt.Sprintf("%x-%x", randToken[:2], randToken[2:])
s.server.db.Exec(`UPDATE users u SET discord_token = $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, _token, s.charID) database.Exec(`UPDATE users u SET discord_token = $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, _token, s.CharID)
} }
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.discord.success, _token)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.discord.success, _token))
} else { } else {
sendDisabledCommandMessage(s, commands["Discord"]) sendDisabledCommandMessage(s, commands["Discord"])
} }
@@ -406,7 +411,7 @@ func parseChatCommand(s *Session, command string) {
if commands["Help"].Enabled || s.isOp() { if commands["Help"].Enabled || s.isOp() {
for _, command := range commands { for _, command := range commands {
if command.Enabled || s.isOp() { if command.Enabled || s.isOp() {
sendServerChatMessage(s, fmt.Sprintf("%s%s: %s", s.server.erupeConfig.CommandPrefix, command.Prefix, command.Description)) sendServerChatMessage(s, fmt.Sprintf("%s%s: %s", config.GetConfig().CommandPrefix, command.Prefix, command.Description))
} }
} }
} else { } else {
@@ -418,21 +423,24 @@ func parseChatCommand(s *Session, command string) {
func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCastBinary) pkt := p.(*mhfpacket.MsgSysCastBinary)
tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x03 && len(pkt.RawDataPayload) == 0x10 { if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x03 && len(pkt.RawDataPayload) == 0x10 {
if tmp.ReadUint16() == 0x0002 && tmp.ReadUint8() == 0x18 { if tmp.ReadUint16() == 0x0002 && tmp.ReadUint8() == 0x18 {
var timer bool var timer bool
s.server.db.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&timer) database.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&timer)
if timer { if timer {
_ = tmp.ReadBytes(9) _ = tmp.ReadBytes(9)
tmp.SetLE() tmp.SetLE()
frame := tmp.ReadUint32() frame := tmp.ReadUint32()
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.timer, frame/30/60/60, frame/30/60, frame/30%60, int(math.Round(float64(frame%30*100)/3)), frame)) sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.timer, frame/30/60/60, frame/30/60, frame/30%60, int(math.Round(float64(frame%30*100)/3)), frame))
} }
} }
} }
if s.server.erupeConfig.DebugOptions.QuestTools { if config.GetConfig().DebugOptions.QuestTools {
if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x02 && len(pkt.RawDataPayload) > 32 { if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x02 && len(pkt.RawDataPayload) > 32 {
// This is only correct most of the time // This is only correct most of the time
tmp.ReadBytes(20) tmp.ReadBytes(20)
@@ -440,7 +448,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
x := tmp.ReadFloat32() x := tmp.ReadFloat32()
y := tmp.ReadFloat32() y := tmp.ReadFloat32()
z := tmp.ReadFloat32() z := tmp.ReadFloat32()
s.logger.Debug("Coord", zap.Float32s("XYZ", []float32{x, y, z})) s.Logger.Debug("Coord", zap.Float32s("XYZ", []float32{x, y, z}))
} }
} }
@@ -463,7 +471,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
msgBinTargeted = &binpacket.MsgBinTargeted{} msgBinTargeted = &binpacket.MsgBinTargeted{}
err := msgBinTargeted.Parse(tmp) err := msgBinTargeted.Parse(tmp)
if err != nil { if err != nil {
s.logger.Warn("Failed to parse targeted cast binary") s.Logger.Warn("Failed to parse targeted cast binary")
return return
} }
realPayload = msgBinTargeted.RawDataPayload realPayload = msgBinTargeted.RawDataPayload
@@ -485,19 +493,19 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
bf.SetLE() bf.SetLE()
chatMessage := &binpacket.MsgBinChat{} chatMessage := &binpacket.MsgBinChat{}
chatMessage.Parse(bf) chatMessage.Parse(bf)
if strings.HasPrefix(chatMessage.Message, s.server.erupeConfig.CommandPrefix) { if strings.HasPrefix(chatMessage.Message, config.GetConfig().CommandPrefix) {
parseChatCommand(s, chatMessage.Message) parseChatCommand(s, chatMessage.Message)
return return
} }
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld { if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message) s.Server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
} }
} }
} }
// Make the response to forward to the other client(s). // Make the response to forward to the other client(s).
resp := &mhfpacket.MsgSysCastedBinary{ resp := &mhfpacket.MsgSysCastedBinary{
CharID: s.charID, CharID: s.CharID,
BroadcastType: pkt.BroadcastType, // (The client never uses Type0 upon receiving) BroadcastType: pkt.BroadcastType, // (The client never uses Type0 upon receiving)
MessageType: pkt.MessageType, MessageType: pkt.MessageType,
RawDataPayload: realPayload, RawDataPayload: realPayload,
@@ -506,7 +514,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
// Send to the proper recipients. // Send to the proper recipients.
switch pkt.BroadcastType { switch pkt.BroadcastType {
case BroadcastTypeWorld: case BroadcastTypeWorld:
s.server.WorldcastMHF(resp, s, nil) s.Server.WorldcastMHF(resp, s, nil)
case BroadcastTypeStage: case BroadcastTypeStage:
if returnToSender { if returnToSender {
s.stage.BroadcastMHF(resp, nil) s.stage.BroadcastMHF(resp, nil)
@@ -515,16 +523,16 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
} }
case BroadcastTypeServer: case BroadcastTypeServer:
if pkt.MessageType == 1 { if pkt.MessageType == 1 {
raviSema := s.server.getRaviSemaphore() raviSema := s.Server.getRaviSemaphore()
if raviSema != nil { if raviSema != nil {
raviSema.BroadcastMHF(resp, s) raviSema.BroadcastMHF(resp, s)
} }
} else { } else {
s.server.BroadcastMHF(resp, s) s.Server.BroadcastMHF(resp, s)
} }
case BroadcastTypeTargeted: case BroadcastTypeTargeted:
for _, targetID := range (*msgBinTargeted).TargetCharIDs { for _, targetID := range (*msgBinTargeted).TargetCharIDs {
char := s.server.FindSessionByCharID(targetID) char := s.Server.FindSessionByCharID(targetID)
if char != nil { if char != nil {
char.QueueSendMHF(resp) char.QueueSendMHF(resp)

View File

@@ -3,9 +3,11 @@ package channelserver
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/bfutil" "erupe-ce/utils/bfutil"
"erupe-ce/utils/db"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/server/channelserver/compression/nullcomp" "erupe-ce/server/channelserver/compression/nullcomp"
@@ -58,8 +60,8 @@ type CharacterSaveData struct {
func getPointers() map[SavePointer]int { func getPointers() map[SavePointer]int {
pointers := map[SavePointer]int{pGender: 81, lBookshelfData: 5576} pointers := map[SavePointer]int{pGender: 81, lBookshelfData: 5576}
switch _config.ErupeConfig.ClientID { switch config.GetConfig().ClientID {
case _config.ZZ: case config.ZZ:
pointers[pWeaponID] = 128522 pointers[pWeaponID] = 128522
pointers[pWeaponType] = 128789 pointers[pWeaponType] = 128789
pointers[pHouseTier] = 129900 pointers[pHouseTier] = 129900
@@ -72,9 +74,9 @@ func getPointers() map[SavePointer]int {
pointers[pGardenData] = 142424 pointers[pGardenData] = 142424
pointers[pRP] = 142614 pointers[pRP] = 142614
pointers[pKQF] = 146720 pointers[pKQF] = 146720
case _config.Z2, _config.Z1, _config.G101, _config.G10, _config.G91, _config.G9, _config.G81, _config.G8, case config.Z2, config.Z1, config.G101, config.G10, config.G91, config.G9, config.G81, config.G8,
_config.G7, _config.G61, _config.G6, _config.G52, _config.G51, _config.G5, _config.GG, _config.G32, _config.G31, config.G7, config.G61, config.G6, config.G52, config.G51, config.G5, config.GG, config.G32, config.G31,
_config.G3, _config.G2, _config.G1: config.G3, config.G2, config.G1:
pointers[pWeaponID] = 92522 pointers[pWeaponID] = 92522
pointers[pWeaponType] = 92789 pointers[pWeaponType] = 92789
pointers[pHouseTier] = 93900 pointers[pHouseTier] = 93900
@@ -87,7 +89,7 @@ func getPointers() map[SavePointer]int {
pointers[pGardenData] = 106424 pointers[pGardenData] = 106424
pointers[pRP] = 106614 pointers[pRP] = 106614
pointers[pKQF] = 110720 pointers[pKQF] = 110720
case _config.F5, _config.F4: case config.F5, config.F4:
pointers[pWeaponID] = 60522 pointers[pWeaponID] = 60522
pointers[pWeaponType] = 60789 pointers[pWeaponType] = 60789
pointers[pHouseTier] = 61900 pointers[pHouseTier] = 61900
@@ -98,7 +100,7 @@ func getPointers() map[SavePointer]int {
pointers[pGalleryData] = 72064 pointers[pGalleryData] = 72064
pointers[pGardenData] = 74424 pointers[pGardenData] = 74424
pointers[pRP] = 74614 pointers[pRP] = 74614
case _config.S6: case config.S6:
pointers[pWeaponID] = 12522 pointers[pWeaponID] = 12522
pointers[pWeaponType] = 12789 pointers[pWeaponType] = 12789
pointers[pHouseTier] = 13900 pointers[pHouseTier] = 13900
@@ -110,24 +112,28 @@ func getPointers() map[SavePointer]int {
pointers[pGardenData] = 26424 pointers[pGardenData] = 26424
pointers[pRP] = 26614 pointers[pRP] = 26614
} }
if _config.ErupeConfig.ClientID == _config.G5 { if config.GetConfig().ClientID == config.G5 {
pointers[lBookshelfData] = 5548 pointers[lBookshelfData] = 5548
} else if _config.ErupeConfig.ClientID <= _config.GG { } else if config.GetConfig().ClientID <= config.GG {
pointers[lBookshelfData] = 4520 pointers[lBookshelfData] = 4520
} }
return pointers 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) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to get savedata", zap.Error(err), zap.Uint32("charID", charID)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
result, err := database.Query("SELECT id, savedata, is_new_character, name FROM characters WHERE id = $1", charID)
if err != nil {
s.Logger.Error("Failed to get savedata", zap.Error(err), zap.Uint32("charID", charID))
return nil, err return nil, err
} }
defer result.Close() defer result.Close()
if !result.Next() { if !result.Next() {
err = errors.New("no savedata found") err = errors.New("no savedata found")
s.logger.Error("No savedata found", zap.Uint32("charID", charID)) s.Logger.Error("No savedata found", zap.Uint32("charID", charID))
return nil, err return nil, err
} }
@@ -136,7 +142,7 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
} }
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))
return nil, err return nil, err
} }
@@ -146,7 +152,7 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
err = saveData.Decompress() err = saveData.Decompress()
if err != nil { if err != nil {
s.logger.Error("Failed to decompress savedata", zap.Error(err)) s.Logger.Error("Failed to decompress savedata", zap.Error(err))
return nil, err return nil, err
} }
@@ -156,6 +162,10 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
} }
func (save *CharacterSaveData) Save(s *Session) { func (save *CharacterSaveData) Save(s *Session) {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if !s.kqfOverride { if !s.kqfOverride {
s.kqf = save.KQF s.kqf = save.KQF
} else { } else {
@@ -164,10 +174,10 @@ func (save *CharacterSaveData) Save(s *Session) {
save.updateSaveDataWithStruct() save.updateSaveDataWithStruct()
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= 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 { } else {
@@ -175,14 +185,14 @@ func (save *CharacterSaveData) Save(s *Session) {
save.compSave = save.decompSave save.compSave = save.decompSave
} }
_, err := s.server.db.Exec(`UPDATE characters SET savedata=$1, is_new_character=false, hr=$2, gr=$3, is_female=$4, weapon_type=$5, weapon_id=$6 WHERE id=$7 _, err = database.Exec(`UPDATE characters SET savedata=$1, is_new_character=false, hr=$2, gr=$3, is_female=$4, weapon_type=$5, weapon_id=$6 WHERE id=$7
`, save.compSave, save.HR, save.GR, save.Gender, save.WeaponType, save.WeaponID, save.CharID) `, save.compSave, save.HR, 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))
} }
s.server.db.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7 database.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7
`, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.charID) `, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.CharID)
} }
func (save *CharacterSaveData) Compress() error { func (save *CharacterSaveData) Compress() error {
@@ -207,10 +217,10 @@ 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)
if _config.ErupeConfig.ClientID >= _config.F4 { if config.GetConfig().ClientID >= config.F4 {
copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes)
} }
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF) copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF)
} }
} }
@@ -224,7 +234,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
save.Gender = false save.Gender = false
} }
if !save.IsNewCharacter { if !save.IsNewCharacter {
if _config.ErupeConfig.ClientID >= _config.S6 { if config.GetConfig().ClientID >= config.S6 {
save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2])
save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5]
save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195]
@@ -235,12 +245,12 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
save.WeaponType = save.decompSave[save.Pointers[pWeaponType]] save.WeaponType = save.decompSave[save.Pointers[pWeaponType]]
save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2]) save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2])
save.HR = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHR] : save.Pointers[pHR]+2]) save.HR = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHR] : save.Pointers[pHR]+2])
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
if save.HR == uint16(999) { if save.HR == uint16(999) {
save.GR = grpToGR(int(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4]))) save.GR = grpToGR(int(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])))
} }
} }
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8]
} }
} }
@@ -250,5 +260,5 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
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, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -3,7 +3,9 @@ package channelserver
import ( import (
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -11,15 +13,15 @@ import (
func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysEnumerateClient) pkt := p.(*mhfpacket.MsgSysEnumerateClient)
s.server.stagesLock.RLock() s.Server.stagesLock.RLock()
stage, ok := s.server.stages[pkt.StageID] stage, ok := s.Server.stages[pkt.StageID]
if !ok { if !ok {
s.server.stagesLock.RUnlock() s.Server.stagesLock.RUnlock()
s.logger.Warn("Can't enumerate clients for stage that doesn't exist!", zap.String("stageID", pkt.StageID)) s.Logger.Warn("Can't enumerate clients for stage that doesn't exist!", zap.String("stageID", pkt.StageID))
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
s.server.stagesLock.RUnlock() s.Server.stagesLock.RUnlock()
// Read-lock the stage and make the response with all of the charID's in the stage. // Read-lock the stage and make the response with all of the charID's in the stage.
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
@@ -52,23 +54,26 @@ func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {
} }
stage.RUnlock() stage.RUnlock()
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
s.logger.Debug("MsgSysEnumerateClient Done!") s.Logger.Debug("MsgSysEnumerateClient Done!")
} }
func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfListMember) pkt := p.(*mhfpacket.MsgMhfListMember)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var csv string var csv string
var count uint32 var count uint32
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(0) // Blacklist count resp.WriteUint32(0) // Blacklist count
err := s.server.db.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.charID).Scan(&csv) err = database.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.CharID).Scan(&csv)
if err == nil { if err == nil {
cids := stringsupport.CSVElems(csv) cids := stringsupport.CSVElems(csv)
for _, cid := range cids { for _, cid := range cids {
var name string var name string
err = s.server.db.QueryRow("SELECT name FROM characters WHERE id=$1", cid).Scan(&name) err = database.QueryRow("SELECT name FROM characters WHERE id=$1", cid).Scan(&name)
if err != nil { if err != nil {
continue continue
} }
@@ -80,36 +85,40 @@ func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) {
} }
resp.Seek(0, 0) resp.Seek(0, 0)
resp.WriteUint32(count) resp.WriteUint32(count)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOprMember) pkt := p.(*mhfpacket.MsgMhfOprMember)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var csv string var csv string
for _, cid := range pkt.CharIDs { for _, cid := range pkt.CharIDs {
if pkt.Blacklist { if pkt.Blacklist {
err := s.server.db.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.charID).Scan(&csv) err := database.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.CharID).Scan(&csv)
if err == nil { if err == nil {
if pkt.Operation { if pkt.Operation {
csv = stringsupport.CSVRemove(csv, int(cid)) csv = stringsupport.CSVRemove(csv, int(cid))
} else { } else {
csv = stringsupport.CSVAdd(csv, int(cid)) csv = stringsupport.CSVAdd(csv, int(cid))
} }
s.server.db.Exec("UPDATE characters SET blocked=$1 WHERE id=$2", csv, s.charID) database.Exec("UPDATE characters SET blocked=$1 WHERE id=$2", csv, s.CharID)
} }
} else { // Friendlist } else { // Friendlist
err := s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&csv) err := database.QueryRow("SELECT friends FROM characters WHERE id=$1", s.CharID).Scan(&csv)
if err == nil { if err == nil {
if pkt.Operation { if pkt.Operation {
csv = stringsupport.CSVRemove(csv, int(cid)) csv = stringsupport.CSVRemove(csv, int(cid))
} else { } else {
csv = stringsupport.CSVAdd(csv, int(cid)) csv = stringsupport.CSVAdd(csv, int(cid))
} }
s.server.db.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.charID) database.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.CharID)
} }
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfShutClient(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfShutClient(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -1,7 +1,8 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/mhfmon" "erupe-ce/utils/mhfmon"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
@@ -21,9 +22,13 @@ import (
func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavedata) pkt := p.(*mhfpacket.MsgMhfSavedata)
characterSaveData, err := GetCharacterSaveData(s, s.charID) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("failed to retrieve character save data from db", zap.Error(err), zap.Uint32("charID", s.charID)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
characterSaveData, err := GetCharacterSaveData(s, s.CharID)
if err != nil {
s.Logger.Error("failed to retrieve character save data from db", zap.Error(err), zap.Uint32("charID", s.CharID))
return return
} }
// Var to hold the decompressed savedata for updating the launcher response fields. // Var to hold the decompressed savedata for updating the launcher response fields.
@@ -32,26 +37,26 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
// diffs themselves are also potentially compressed // diffs themselves are also potentially compressed
diff, err := nullcomp.Decompress(pkt.RawDataPayload) diff, err := nullcomp.Decompress(pkt.RawDataPayload)
if err != nil { if err != nil {
s.logger.Error("Failed to decompress diff", zap.Error(err)) s.Logger.Error("Failed to decompress diff", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
// Perform diff. // Perform diff.
s.logger.Info("Diffing...") s.Logger.Info("Diffing...")
characterSaveData.decompSave = deltacomp.ApplyDataDiff(diff, characterSaveData.decompSave) characterSaveData.decompSave = deltacomp.ApplyDataDiff(diff, characterSaveData.decompSave)
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "savedata") dumpSaveData(s, pkt.RawDataPayload, "savedata")
// Regular blob update. // Regular blob update.
saveData, err := nullcomp.Decompress(pkt.RawDataPayload) saveData, err := nullcomp.Decompress(pkt.RawDataPayload)
if err != nil { if err != nil {
s.logger.Error("Failed to decompress savedata from packet", zap.Error(err)) s.Logger.Error("Failed to decompress savedata from packet", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
if s.server.erupeConfig.SaveDumps.RawEnabled { if config.GetConfig().SaveDumps.RawEnabled {
dumpSaveData(s, saveData, "raw-savedata") dumpSaveData(s, saveData, "raw-savedata")
} }
s.logger.Info("Updating save with blob") s.Logger.Info("Updating save with blob")
characterSaveData.decompSave = saveData characterSaveData.decompSave = saveData
} }
characterSaveData.updateStructWithSaveData() characterSaveData.updateStructWithSaveData()
@@ -61,22 +66,22 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
s.Name = characterSaveData.Name s.Name = characterSaveData.Name
} }
if characterSaveData.Name == s.Name || _config.ErupeConfig.ClientID <= _config.S10 { if characterSaveData.Name == s.Name || config.GetConfig().ClientID <= config.S10 {
characterSaveData.Save(s) characterSaveData.Save(s)
s.logger.Info("Wrote recompressed savedata back to DB.") s.Logger.Info("Wrote recompressed savedata back to DB.")
} else { } else {
s.rawConn.Close() s.rawConn.Close()
s.logger.Warn("Save cancelled due to corruption.") s.Logger.Warn("Save cancelled due to corruption.")
if s.server.erupeConfig.DeleteOnSaveCorruption { if config.GetConfig().DeleteOnSaveCorruption {
s.server.db.Exec("UPDATE characters SET deleted=true WHERE id=$1", s.charID) database.Exec("UPDATE characters SET deleted=true WHERE id=$1", s.CharID)
} }
return return
} }
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID) _, err = database.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to update character name in db", zap.Error(err)) s.Logger.Error("Failed to update character name in db", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func grpToGR(n int) uint16 { func grpToGR(n int) uint16 {
@@ -115,83 +120,95 @@ func grpToGR(n int) uint16 {
} }
func dumpSaveData(s *Session, data []byte, suffix string) { func dumpSaveData(s *Session, data []byte, suffix string) {
if !s.server.erupeConfig.SaveDumps.Enabled { if !config.GetConfig().SaveDumps.Enabled {
return return
} else { } else {
dir := filepath.Join(s.server.erupeConfig.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID)) dir := filepath.Join(config.GetConfig().SaveDumps.OutputDir, fmt.Sprintf("%d", s.CharID))
path := filepath.Join(s.server.erupeConfig.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID), fmt.Sprintf("%d_%s.bin", s.charID, suffix)) path := filepath.Join(config.GetConfig().SaveDumps.OutputDir, fmt.Sprintf("%d", s.CharID), fmt.Sprintf("%d_%s.bin", s.CharID, suffix))
_, err := os.Stat(dir) _, err := os.Stat(dir)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = os.MkdirAll(dir, os.ModePerm) err = os.MkdirAll(dir, os.ModePerm)
if err != nil { if err != nil {
s.logger.Error("Error dumping savedata, could not create folder") s.Logger.Error("Error dumping savedata, could not create folder")
return return
} }
} else { } else {
s.logger.Error("Error dumping savedata") s.Logger.Error("Error dumping savedata")
return return
} }
} }
err = os.WriteFile(path, data, 0644) err = os.WriteFile(path, data, 0644)
if err != nil { if err != nil {
s.logger.Error("Error dumping savedata, could not write file", zap.Error(err)) s.Logger.Error("Error dumping savedata, could not write file", zap.Error(err))
} }
} }
} }
func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoaddata) pkt := p.(*mhfpacket.MsgMhfLoaddata)
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin")); err == nil { database, err := db.GetDB()
data, _ := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin")) if err != nil {
doAckBufSucceed(s, pkt.AckHandle, data) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if _, err := os.Stat(filepath.Join(config.GetConfig().BinPath, "save_override.bin")); err == nil {
data, _ := os.ReadFile(filepath.Join(config.GetConfig().BinPath, "save_override.bin"))
DoAckBufSucceed(s, pkt.AckHandle, data)
return return
} }
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT savedata FROM characters WHERE id = $1", s.charID).Scan(&data) err = database.QueryRow("SELECT savedata FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil || len(data) == 0 { if err != nil || len(data) == 0 {
s.logger.Warn(fmt.Sprintf("Failed to load savedata (CID: %d)", s.charID), zap.Error(err)) s.Logger.Warn(fmt.Sprintf("Failed to load savedata (CID: %d)", s.CharID), zap.Error(err))
s.rawConn.Close() // Terminate the connection s.rawConn.Close() // Terminate the connection
return return
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
decompSaveData, err := nullcomp.Decompress(data) decompSaveData, err := nullcomp.Decompress(data)
if err != nil { if err != nil {
s.logger.Error("Failed to decompress savedata", zap.Error(err)) s.Logger.Error("Failed to decompress savedata", zap.Error(err))
} }
bf := byteframe.NewByteFrameFromBytes(decompSaveData) bf := byteframe.NewByteFrameFromBytes(decompSaveData)
bf.Seek(88, io.SeekStart) bf.Seek(88, io.SeekStart)
name := bf.ReadNullTerminatedBytes() name := bf.ReadNullTerminatedBytes()
s.server.userBinaryPartsLock.Lock() s.Server.userBinaryPartsLock.Lock()
s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: 1}] = append(name, []byte{0x00}...) s.Server.userBinaryParts[userBinaryPartID{charID: s.CharID, index: 1}] = append(name, []byte{0x00}...)
s.server.userBinaryPartsLock.Unlock() s.Server.userBinaryPartsLock.Unlock()
s.Name = stringsupport.SJISToUTF8(name) s.Name = stringsupport.SJISToUTF8(name)
} }
func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveScenarioData) pkt := p.(*mhfpacket.MsgMhfSaveScenarioData)
dumpSaveData(s, pkt.RawDataPayload, "scenario") database, err := db.GetDB()
_, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Error("Failed to update scenario data in db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) dumpSaveData(s, pkt.RawDataPayload, "scenario")
_, err = database.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.CharID)
if err != nil {
s.Logger.Error("Failed to update scenario data in db", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadScenarioData) pkt := p.(*mhfpacket.MsgMhfLoadScenarioData)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var scenarioData []byte var scenarioData []byte
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData) err = database.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.CharID).Scan(&scenarioData)
if err != nil || len(scenarioData) < 10 { if err != nil || len(scenarioData) < 10 {
s.logger.Error("Failed to load scenariodata", zap.Error(err)) s.Logger.Error("Failed to load scenariodata", zap.Error(err))
bf.WriteBytes(make([]byte, 10)) bf.WriteBytes(make([]byte, 10))
} else { } else {
bf.WriteBytes(scenarioData) bf.WriteBytes(scenarioData)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
var paperGiftData = map[uint32][]PaperGift{ var paperGiftData = map[uint32][]PaperGift{
@@ -1509,7 +1526,7 @@ func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
} }
default: default:
if pkt.Unk2 < 1000 { if pkt.Unk2 < 1000 {
s.logger.Info("PaperData request for unknown type", zap.Uint32("Unk2", pkt.Unk2)) s.Logger.Info("PaperData request for unknown type", zap.Uint32("Unk2", pkt.Unk2))
} }
} }
@@ -1518,7 +1535,7 @@ func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
if ok { if ok {
paperGift = paperGiftData[pkt.Unk2] paperGift = paperGiftData[pkt.Unk2]
} else { } else {
s.logger.Info("PaperGift request for unknown type", zap.Uint32("Unk2", pkt.Unk2)) s.Logger.Info("PaperGift request for unknown type", zap.Uint32("Unk2", pkt.Unk2))
} }
for _, gift := range paperGift { for _, gift := range paperGift {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
@@ -1528,7 +1545,7 @@ func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(gift.Unk3) bf.WriteUint16(gift.Unk3)
data = append(data, bf) data = append(data, bf)
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} else if pkt.Unk2 == 0 { } else if pkt.Unk2 == 0 {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(len(paperMissions.Timetables))) bf.WriteUint16(uint16(len(paperMissions.Timetables)))
@@ -1546,7 +1563,7 @@ func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(mdata.Reward2ID) bf.WriteUint16(mdata.Reward2ID)
bf.WriteUint8(mdata.Reward2Quantity) bf.WriteUint8(mdata.Reward2Quantity)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
for _, pdata := range paperData { for _, pdata := range paperData {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
@@ -1559,7 +1576,7 @@ func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt16(pdata.Unk6) bf.WriteInt16(pdata.Unk6)
data = append(data, bf) data = append(data, bf)
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
} }

View File

@@ -1,10 +1,12 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"fmt"
"time" "time"
"go.uber.org/zap" "go.uber.org/zap"
@@ -32,7 +34,11 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
var itemDists []Distribution var itemDists []Distribution
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
rows, err := s.server.db.Queryx(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`
SELECT d.id, event_name, description, COALESCE(rights, 0) AS rights, COALESCE(selection, false) AS selection, times_acceptable, SELECT d.id, event_name, description, COALESCE(rights, 0) AS rights, COALESCE(selection, false) AS selection, times_acceptable,
COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr, COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr,
COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr, COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr,
@@ -44,7 +50,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
COALESCE(deadline, TO_TIMESTAMP(0)) AS deadline COALESCE(deadline, TO_TIMESTAMP(0)) AS deadline
FROM distribution d FROM distribution d
WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC
`, s.charID, pkt.DistType) `, s.CharID, pkt.DistType)
if err == nil { if err == nil {
var itemDist Distribution var itemDist Distribution
@@ -64,7 +70,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(dist.Rights) bf.WriteUint32(dist.Rights)
bf.WriteUint16(dist.TimesAcceptable) bf.WriteUint16(dist.TimesAcceptable)
bf.WriteUint16(dist.TimesAccepted) bf.WriteUint16(dist.TimesAccepted)
if _config.ErupeConfig.ClientID >= _config.G9 { if config.GetConfig().ClientID >= config.G9 {
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
} }
bf.WriteInt16(dist.MinHR) bf.WriteInt16(dist.MinHR)
@@ -73,29 +79,29 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt16(dist.MaxSR) bf.WriteInt16(dist.MaxSR)
bf.WriteInt16(dist.MinGR) bf.WriteInt16(dist.MinGR)
bf.WriteInt16(dist.MaxGR) bf.WriteInt16(dist.MaxGR)
if _config.ErupeConfig.ClientID >= _config.G7 { if config.GetConfig().ClientID >= config.G7 {
bf.WriteUint8(0) // Unk bf.WriteUint8(0) // Unk
} }
if _config.ErupeConfig.ClientID >= _config.G6 { if config.GetConfig().ClientID >= config.G6 {
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
} }
if _config.ErupeConfig.ClientID >= _config.G8 { if config.GetConfig().ClientID >= config.G8 {
if dist.Selection { if dist.Selection {
bf.WriteUint8(2) // Selection bf.WriteUint8(2) // Selection
} else { } else {
bf.WriteUint8(0) bf.WriteUint8(0)
} }
} }
if _config.ErupeConfig.ClientID >= _config.G7 { if config.GetConfig().ClientID >= config.G7 {
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
} }
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
bf.WriteUint8(0) // Unk bf.WriteUint8(0) // Unk
} }
ps.Uint8(bf, dist.EventName, true) ps.Uint8(bf, dist.EventName, true)
k := 6 k := 6
if _config.ErupeConfig.ClientID >= _config.G8 { if config.GetConfig().ClientID >= config.G8 {
k = 13 k = 13
} }
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
@@ -104,7 +110,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(0) bf.WriteUint32(0)
} }
} }
if _config.ErupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
i := uint8(0) i := uint8(0)
bf.WriteUint8(i) bf.WriteUint8(i)
if i <= 10 { if i <= 10 {
@@ -116,7 +122,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
} }
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
type DistributionItem struct { type DistributionItem struct {
@@ -127,8 +133,12 @@ type DistributionItem struct {
} }
func getDistributionItems(s *Session, i uint32) []DistributionItem { func getDistributionItems(s *Session, i uint32) []DistributionItem {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var distItems []DistributionItem var distItems []DistributionItem
rows, err := s.server.db.Queryx(`SELECT id, item_type, COALESCE(item_id, 0) AS item_id, COALESCE(quantity, 0) AS quantity FROM distribution_items WHERE distribution_id=$1`, i) rows, err := database.Queryx(`SELECT id, item_type, COALESCE(item_id, 0) AS item_id, COALESCE(quantity, 0) AS quantity FROM distribution_items WHERE distribution_id=$1`, i)
if err == nil { if err == nil {
var distItem DistributionItem var distItem DistributionItem
for rows.Next() { for rows.Next() {
@@ -152,17 +162,21 @@ func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(item.ItemType) bf.WriteUint8(item.ItemType)
bf.WriteUint32(item.ItemID) bf.WriteUint32(item.ItemID)
bf.WriteUint32(item.Quantity) bf.WriteUint32(item.Quantity)
if _config.ErupeConfig.ClientID >= _config.G8 { if config.GetConfig().ClientID >= config.G8 {
bf.WriteUint32(item.ID) bf.WriteUint32(item.ID)
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireDistItem) pkt := p.(*mhfpacket.MsgMhfAcquireDistItem)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.DistributionID > 0 { if pkt.DistributionID > 0 {
_, err := s.server.db.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.charID) _, err := database.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.CharID)
if err == nil { if err == nil {
distItems := getDistributionItems(s, pkt.DistributionID) distItems := getDistributionItems(s, pkt.DistributionID)
for _, item := range distItems { for _, item := range distItems {
@@ -170,13 +184,13 @@ func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
case 17: case 17:
_ = addPointNetcafe(s, int(item.Quantity)) _ = addPointNetcafe(s, int(item.Quantity))
case 19: case 19:
s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) database.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.CharID)
case 20: case 20:
s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) database.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.CharID)
case 21: case 21:
s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) database.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.CharID)
case 23: case 23:
saveData, err := GetCharacterSaveData(s, s.charID) saveData, err := GetCharacterSaveData(s, s.CharID)
if err == nil { if err == nil {
saveData.RP += uint16(item.Quantity) saveData.RP += uint16(item.Quantity)
saveData.Save(s) saveData.Save(s)
@@ -185,20 +199,24 @@ func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
} }
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetDistDescription) pkt := p.(*mhfpacket.MsgMhfGetDistDescription)
var desc string database, err := db.GetDB()
err := s.server.db.QueryRow("SELECT description FROM distribution WHERE id = $1", pkt.DistributionID).Scan(&desc)
if err != nil { if err != nil {
s.logger.Error("Error parsing item distribution description", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) }
var desc string
err = database.QueryRow("SELECT description FROM distribution WHERE id = $1", pkt.DistributionID).Scan(&desc)
if err != nil {
s.Logger.Error("Error parsing item distribution description", zap.Error(err))
DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
ps.Uint16(bf, desc, true) ps.Uint16(bf, desc, true)
ps.Uint16(bf, "", false) ps.Uint16(bf, "", false)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -2,9 +2,11 @@ package channelserver
import ( import (
"encoding/hex" "encoding/hex"
_config "erupe-ce/config" config "erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt"
"time" "time"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
@@ -12,10 +14,18 @@ import (
) )
func cleanupDiva(s *Session) { func cleanupDiva(s *Session) {
s.server.db.Exec("DELETE FROM events WHERE event_type='diva'") database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("DELETE FROM events WHERE event_type='diva'")
} }
func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 { func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
timestamps := make([]uint32, 6) timestamps := make([]uint32, 6)
midnight := gametime.TimeMidnight() midnight := gametime.TimeMidnight()
if debug && start <= 3 { if debug && start <= 3 {
@@ -49,7 +59,7 @@ func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
cleanupDiva(s) cleanupDiva(s)
// Generate a new diva defense, starting midnight tomorrow // Generate a new diva defense, starting midnight tomorrow
start = uint32(midnight.Add(24 * time.Hour).Unix()) start = uint32(midnight.Add(24 * time.Hour).Unix())
s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('diva', to_timestamp($1)::timestamp without time zone)", start) database.Exec("INSERT INTO events (event_type, start_time) VALUES ('diva', to_timestamp($1)::timestamp without time zone)", start)
} }
timestamps[0] = start timestamps[0] = start
timestamps[1] = timestamps[0] + 601200 timestamps[1] = timestamps[0] + 601200
@@ -63,29 +73,32 @@ func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdSchedule) pkt := p.(*mhfpacket.MsgMhfGetUdSchedule)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
id, start := uint32(0xCAFEBEEF), uint32(0) id, start := uint32(0xCAFEBEEF), uint32(0)
rows, _ := s.server.db.Queryx("SELECT id, (EXTRACT(epoch FROM start_time)::int) as start_time FROM events WHERE event_type='diva'") rows, _ := database.Queryx("SELECT id, (EXTRACT(epoch FROM start_time)::int) as start_time FROM events WHERE event_type='diva'")
for rows.Next() { for rows.Next() {
rows.Scan(&id, &start) rows.Scan(&id, &start)
} }
var timestamps []uint32 var timestamps []uint32
if s.server.erupeConfig.DebugOptions.DivaOverride >= 0 { if config.GetConfig().DebugOptions.DivaOverride >= 0 {
if s.server.erupeConfig.DebugOptions.DivaOverride == 0 { if config.GetConfig().DebugOptions.DivaOverride == 0 {
if s.server.erupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 36)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 36))
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 32)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 32))
} }
return return
} }
timestamps = generateDivaTimestamps(s, uint32(s.server.erupeConfig.DebugOptions.DivaOverride), true) timestamps = generateDivaTimestamps(s, uint32(config.GetConfig().DebugOptions.DivaOverride), true)
} else { } else {
timestamps = generateDivaTimestamps(s, start, false) timestamps = generateDivaTimestamps(s, start, false)
} }
if s.server.erupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
bf.WriteUint32(id) bf.WriteUint32(id)
} }
for i := range timestamps { for i := range timestamps {
@@ -97,7 +110,7 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0x02) // Unk 00000010 bf.WriteUint16(0x02) // Unk 00000010
bf.WriteUint16(0x02) // Unk 00000010 bf.WriteUint16(0x02) // Unk 00000010
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetUdInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdInfo(s *Session, p mhfpacket.MHFPacket) {
@@ -117,45 +130,45 @@ func handleMsgMhfGetUdInfo(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint32(uint32(udInfo.EndTime.Unix())) resp.WriteUint32(uint32(udInfo.EndTime.Unix()))
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfGetKijuInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetKijuInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetKijuInfo) pkt := p.(*mhfpacket.MsgMhfGetKijuInfo)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("04965C959782CC8B468EEC00000000000000000000000000000000000000000000815C82A082E782B582DC82A982BA82CC82AB82B682E3815C0A965C959782C682CD96D282E98E7682A281420A95B782AD8ED282C997458B4382F0975E82A682E98142000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001018BAD8C8282CC8B468EEC00000000000000000000000000000000000000000000815C82AB82E582A482B082AB82CC82AB82B682E3815C0A8BAD8C8282C682CD8BAD82A290BA904681420A95B782AD8ED282CC97CD82F08CA482AC909F82DC82B78142200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003138C8B8F5782CC8B468EEC00000000000000000000000000000000000000000000815C82AF82C182B582E382A482CC82AB82B682E3815C0A8C8B8F5782C682CD8A6D8CC582BD82E9904D978A81420A8F5782DF82E982D982C782C98EEB906C82BD82BF82CC90B8905F97CD82C682C882E9814200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041189CC8CEC82CC8B468EEC00000000000000000000000000000000000000000000815C82A482BD82DC82E082E882CC82AB82B682E3815C0A89CC8CEC82C682CD89CC955082CC8CEC82E881420A8F5782DF82E982D982C782C98EEB906C82BD82BF82CC8E7882A682C682C882E9814220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000212") data, _ := hex.DecodeString("04965C959782CC8B468EEC00000000000000000000000000000000000000000000815C82A082E782B582DC82A982BA82CC82AB82B682E3815C0A965C959782C682CD96D282E98E7682A281420A95B782AD8ED282C997458B4382F0975E82A682E98142000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001018BAD8C8282CC8B468EEC00000000000000000000000000000000000000000000815C82AB82E582A482B082AB82CC82AB82B682E3815C0A8BAD8C8282C682CD8BAD82A290BA904681420A95B782AD8ED282CC97CD82F08CA482AC909F82DC82B78142200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003138C8B8F5782CC8B468EEC00000000000000000000000000000000000000000000815C82AF82C182B582E382A482CC82AB82B682E3815C0A8C8B8F5782C682CD8A6D8CC582BD82E9904D978A81420A8F5782DF82E982D982C782C98EEB906C82BD82BF82CC90B8905F97CD82C682C882E9814200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041189CC8CEC82CC8B468EEC00000000000000000000000000000000000000000000815C82A482BD82DC82E082E882CC82AB82B682E3815C0A89CC8CEC82C682CD89CC955082CC8CEC82E881420A8F5782DF82E982D982C782C98EEB906C82BD82BF82CC8E7882A682C682C882E9814220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000212")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSetKiju(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSetKiju(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetKiju) pkt := p.(*mhfpacket.MsgMhfSetKiju)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfAddUdPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAddUdPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAddUdPoint) pkt := p.(*mhfpacket.MsgMhfAddUdPoint)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetUdMyPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdMyPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdMyPoint) pkt := p.(*mhfpacket.MsgMhfGetUdMyPoint)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("00040000013C000000FA000000000000000000040000007E0000003C02000000000000000000000000000000000000000000000000000002000004CC00000438000000000000000000000000000000000000000000000000000000020000026E00000230000000000000000000020000007D0000007D000000000000000000000000000000000000000000000000000000") data, _ := hex.DecodeString("00040000013C000000FA000000000000000000040000007E0000003C02000000000000000000000000000000000000000000000000000002000004CC00000438000000000000000000000000000000000000000000000000000000020000026E00000230000000000000000000020000007D0000007D000000000000000000000000000000000000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfGetUdTotalPointInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdTotalPointInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdTotalPointInfo) pkt := p.(*mhfpacket.MsgMhfGetUdTotalPointInfo)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("00000000000007A12000000000000F424000000000001E848000000000002DC6C000000000003D090000000000004C4B4000000000005B8D8000000000006ACFC000000000007A1200000000000089544000000000009896800000000000E4E1C00000000001312D0000000000017D78400000000001C9C3800000000002160EC00000000002625A000000000002AEA5400000000002FAF0800000000003473BC0000000000393870000000000042C1D800000000004C4B40000000000055D4A800000000005F5E10000000000008954400000000001C9C3800000000003473BC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020300000000000000000000000000000000000000000000000000000000000000000000000000000000101F1420") data, _ := hex.DecodeString("00000000000007A12000000000000F424000000000001E848000000000002DC6C000000000003D090000000000004C4B4000000000005B8D8000000000006ACFC000000000007A1200000000000089544000000000009896800000000000E4E1C00000000001312D0000000000017D78400000000001C9C3800000000002160EC00000000002625A000000000002AEA5400000000002FAF0800000000003473BC0000000000393870000000000042C1D800000000004C4B40000000000055D4A800000000005F5E10000000000008954400000000001C9C3800000000003473BC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020300000000000000000000000000000000000000000000000000000000000000000000000000000000101F1420")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfGetUdSelectedColorInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdSelectedColorInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdSelectedColorInfo) pkt := p.(*mhfpacket.MsgMhfGetUdSelectedColorInfo)
// Unk // Unk
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x01, 0x01, 0x01, 0x02, 0x03, 0x02, 0x00, 0x00}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x01, 0x01, 0x01, 0x02, 0x03, 0x02, 0x00, 0x00})
} }
func handleMsgMhfGetUdMonsterPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdMonsterPoint(s *Session, p mhfpacket.MHFPacket) {
@@ -287,36 +300,36 @@ func handleMsgMhfGetUdMonsterPoint(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint16(mp.Points) resp.WriteUint16(mp.Points)
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfGetUdDailyPresentList(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdDailyPresentList(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdDailyPresentList) pkt := p.(*mhfpacket.MsgMhfGetUdDailyPresentList)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000") data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfGetUdNormaPresentList(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdNormaPresentList(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdNormaPresentList) pkt := p.(*mhfpacket.MsgMhfGetUdNormaPresentList)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000") data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfAcquireUdItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireUdItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireUdItem) pkt := p.(*mhfpacket.MsgMhfAcquireUdItem)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetUdRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdRanking) pkt := p.(*mhfpacket.MsgMhfGetUdRanking)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetUdMyRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdMyRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdMyRanking) pkt := p.(*mhfpacket.MsgMhfGetUdMyRanking)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("00000515000005150000CEB4000003CE000003CE0000CEB44D49444E494748542D414E47454C0000000000000000000000") data, _ := hex.DecodeString("00000515000005150000CEB4000003CE000003CE0000CEB44D49444E494748542D414E47454C0000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }

View File

@@ -1,9 +1,11 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/token" "erupe-ce/utils/token"
"fmt"
"math" "math"
"time" "time"
@@ -45,7 +47,7 @@ func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) {
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
type activeFeature struct { type activeFeature struct {
@@ -55,7 +57,10 @@ type activeFeature struct {
func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule) pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var features []activeFeature var features []activeFeature
times := []time.Time{ times := []time.Time{
gametime.TimeMidnight().Add(-24 * time.Hour), gametime.TimeMidnight().Add(-24 * time.Hour),
@@ -65,12 +70,12 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
for _, t := range times { for _, t := range times {
var temp activeFeature var temp activeFeature
err := s.server.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, t).StructScan(&temp) err := database.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, t).StructScan(&temp)
if err != nil || temp.StartTime.IsZero() { if err != nil || temp.StartTime.IsZero() {
weapons := token.RNG.Intn(s.server.erupeConfig.GameplayOptions.MaxFeatureWeapons-s.server.erupeConfig.GameplayOptions.MinFeatureWeapons+1) + s.server.erupeConfig.GameplayOptions.MinFeatureWeapons weapons := token.RNG.Intn(config.GetConfig().GameplayOptions.MaxFeatureWeapons-config.GetConfig().GameplayOptions.MinFeatureWeapons+1) + config.GetConfig().GameplayOptions.MinFeatureWeapons
temp = generateFeatureWeapons(weapons) temp = generateFeatureWeapons(weapons)
temp.StartTime = t temp.StartTime = t
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures) database.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures)
} }
features = append(features, temp) features = append(features, temp)
} }
@@ -83,18 +88,18 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(feature.ActiveFeatures) bf.WriteUint32(feature.ActiveFeatures)
bf.WriteUint16(0) bf.WriteUint16(0)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func generateFeatureWeapons(count int) activeFeature { func generateFeatureWeapons(count int) activeFeature {
_max := 14 _max := 14
if _config.ErupeConfig.ClientID < _config.ZZ { if config.GetConfig().ClientID < config.ZZ {
_max = 13 _max = 13
} }
if _config.ErupeConfig.ClientID < _config.G10 { if config.GetConfig().ClientID < config.G10 {
_max = 12 _max = 12
} }
if _config.ErupeConfig.ClientID < _config.GG { if config.GetConfig().ClientID < config.GG {
_max = 11 _max = 11
} }
if count > _max { if count > _max {
@@ -131,14 +136,17 @@ type loginBoost struct {
func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus) pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var loginBoosts []loginBoost var loginBoosts []loginBoost
rows, err := s.server.db.Queryx("SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", s.charID) rows, err := database.Queryx("SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", s.CharID)
if err != nil || s.server.erupeConfig.GameplayOptions.DisableLoginBoost { if err != nil || config.GetConfig().GameplayOptions.DisableLoginBoost {
rows.Close() rows.Close()
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 35))
return return
} }
for rows.Next() { for rows.Next() {
@@ -156,7 +164,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
{WeekReq: 5, Expiration: temp}, {WeekReq: 5, Expiration: temp},
} }
for _, boost := range loginBoosts { for _, boost := range loginBoosts {
s.server.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, s.charID, boost.WeekReq, boost.Expiration, time.Time{}) database.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, s.CharID, boost.WeekReq, boost.Expiration, time.Time{})
} }
} }
@@ -165,7 +173,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
if !boost.Reset.IsZero() && boost.Reset.Before(gametime.TimeAdjusted()) { if !boost.Reset.IsZero() && boost.Reset.Before(gametime.TimeAdjusted()) {
boost.Expiration = gametime.TimeWeekStart() boost.Expiration = gametime.TimeWeekStart()
boost.Reset = time.Time{} boost.Reset = time.Time{}
s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, boost.Expiration, boost.Reset, s.charID, boost.WeekReq) database.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, boost.Expiration, boost.Reset, s.CharID, boost.WeekReq)
} }
boost.WeekCount = uint8((gametime.TimeAdjusted().Unix()-boost.Expiration.Unix())/604800 + 1) boost.WeekCount = uint8((gametime.TimeAdjusted().Unix()-boost.Expiration.Unix())/604800 + 1)
@@ -191,7 +199,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {
@@ -208,13 +216,17 @@ func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {
expiration = gametime.TimeAdjusted().Add(240 * time.Minute) expiration = gametime.TimeAdjusted().Add(240 * time.Minute)
} }
bf.WriteUint32(uint32(expiration.Unix())) bf.WriteUint32(uint32(expiration.Unix()))
s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, gametime.TimeWeekNext(), s.charID, pkt.BoostWeekUsed) database, err := db.GetDB()
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, gametime.TimeWeekNext(), s.CharID, pkt.BoostWeekUsed)
DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfSetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetRestrictionEvent) pkt := p.(*mhfpacket.MsgMhfSetRestrictionEvent)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -1,26 +1,36 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"erupe-ce/utils/token" "erupe-ce/utils/token"
"fmt"
"sort" "sort"
"time" "time"
) )
func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveMezfesData) pkt := p.(*mhfpacket.MsgMhfSaveMezfesData)
s.server.db.Exec(`UPDATE characters SET mezfes=$1 WHERE id=$2`, pkt.RawDataPayload, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`UPDATE characters SET mezfes=$1 WHERE id=$2`, pkt.RawDataPayload, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadMezfesData) pkt := p.(*mhfpacket.MsgMhfLoadMezfesData)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var data []byte var data []byte
s.server.db.QueryRow(`SELECT mezfes FROM characters WHERE id=$1`, s.charID).Scan(&data) database.QueryRow(`SELECT mezfes FROM characters WHERE id=$1`, s.CharID).Scan(&data)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
if len(data) > 0 { if len(data) > 0 {
bf.WriteBytes(data) bf.WriteBytes(data)
@@ -31,13 +41,13 @@ func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(0) bf.WriteUint32(0)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateRanking) pkt := p.(*mhfpacket.MsgMhfEnumerateRanking)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
state := s.server.erupeConfig.DebugOptions.TournamentOverride state := config.GetConfig().DebugOptions.TournamentOverride
// Unk // Unk
// Unk // Unk
// Start? // Start?
@@ -64,7 +74,7 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) // TS Current Time bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) // TS Current Time
bf.WriteUint8(3) bf.WriteUint8(3)
bf.WriteBytes(make([]byte, 4)) bf.WriteBytes(make([]byte, 4))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
return return
} }
bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) // TS Current Time bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) // TS Current Time
@@ -90,18 +100,26 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
psUint16 desc psUint16 desc
*/ */
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func cleanupFesta(s *Session) { func cleanupFesta(s *Session) {
s.server.db.Exec("DELETE FROM events WHERE event_type='festa'") database, err := db.GetDB()
s.server.db.Exec("DELETE FROM festa_registrations") if err != nil {
s.server.db.Exec("DELETE FROM festa_submissions") s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
s.server.db.Exec("DELETE FROM festa_prizes_accepted") }
s.server.db.Exec("UPDATE guild_characters SET trial_vote=NULL") database.Exec("DELETE FROM events WHERE event_type='festa'")
database.Exec("DELETE FROM festa_registrations")
database.Exec("DELETE FROM festa_submissions")
database.Exec("DELETE FROM festa_prizes_accepted")
database.Exec("UPDATE guild_characters SET trial_vote=NULL")
} }
func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 { func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
timestamps := make([]uint32, 5) timestamps := make([]uint32, 5)
midnight := gametime.TimeMidnight() midnight := gametime.TimeMidnight()
if debug && start <= 3 { if debug && start <= 3 {
@@ -132,7 +150,7 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
cleanupFesta(s) cleanupFesta(s)
// Generate a new festa, starting midnight tomorrow // Generate a new festa, starting midnight tomorrow
start = uint32(midnight.Add(24 * time.Hour).Unix()) start = uint32(midnight.Add(24 * time.Hour).Unix())
s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start) database.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start)
} }
timestamps[0] = start timestamps[0] = start
timestamps[1] = timestamps[0] + 604800 timestamps[1] = timestamps[0] + 604800
@@ -167,32 +185,35 @@ type FestaReward struct {
func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfInfoFesta) pkt := p.(*mhfpacket.MsgMhfInfoFesta)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
id, start := uint32(0xDEADBEEF), uint32(0) id, start := uint32(0xDEADBEEF), uint32(0)
rows, _ := s.server.db.Queryx("SELECT id, (EXTRACT(epoch FROM start_time)::int) as start_time FROM events WHERE event_type='festa'") rows, _ := database.Queryx("SELECT id, (EXTRACT(epoch FROM start_time)::int) as start_time FROM events WHERE event_type='festa'")
for rows.Next() { for rows.Next() {
rows.Scan(&id, &start) rows.Scan(&id, &start)
} }
var timestamps []uint32 var timestamps []uint32
if s.server.erupeConfig.DebugOptions.FestaOverride >= 0 { if config.GetConfig().DebugOptions.FestaOverride >= 0 {
if s.server.erupeConfig.DebugOptions.FestaOverride == 0 { if config.GetConfig().DebugOptions.FestaOverride == 0 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
timestamps = generateFestaTimestamps(s, uint32(s.server.erupeConfig.DebugOptions.FestaOverride), true) timestamps = generateFestaTimestamps(s, uint32(config.GetConfig().DebugOptions.FestaOverride), true)
} else { } else {
timestamps = generateFestaTimestamps(s, start, false) timestamps = generateFestaTimestamps(s, start, false)
} }
if timestamps[0] > uint32(gametime.TimeAdjusted().Unix()) { if timestamps[0] > uint32(gametime.TimeAdjusted().Unix()) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
var blueSouls, redSouls uint32 var blueSouls, redSouls uint32
s.server.db.QueryRow(`SELECT COALESCE(SUM(fs.souls), 0) AS souls FROM festa_registrations fr LEFT JOIN festa_submissions fs ON fr.guild_id = fs.guild_id AND fr.team = 'blue'`).Scan(&blueSouls) database.QueryRow(`SELECT COALESCE(SUM(fs.souls), 0) AS souls FROM festa_registrations fr LEFT JOIN festa_submissions fs ON fr.guild_id = fs.guild_id AND fr.team = 'blue'`).Scan(&blueSouls)
s.server.db.QueryRow(`SELECT COALESCE(SUM(fs.souls), 0) AS souls FROM festa_registrations fr LEFT JOIN festa_submissions fs ON fr.guild_id = fs.guild_id AND fr.team = 'red'`).Scan(&redSouls) database.QueryRow(`SELECT COALESCE(SUM(fs.souls), 0) AS souls FROM festa_registrations fr LEFT JOIN festa_submissions fs ON fr.guild_id = fs.guild_id AND fr.team = 'red'`).Scan(&redSouls)
bf.WriteUint32(id) bf.WriteUint32(id)
for _, timestamp := range timestamps { for _, timestamp := range timestamps {
@@ -207,7 +228,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
var trials []FestaTrial var trials []FestaTrial
var trial FestaTrial var trial FestaTrial
rows, _ = s.server.db.Queryx(`SELECT ft.*, rows, _ = database.Queryx(`SELECT ft.*,
COALESCE(CASE COALESCE(CASE
WHEN COUNT(gc.id) FILTER (WHERE fr.team = 'blue' AND gc.trial_vote = ft.id) > WHEN COUNT(gc.id) FILTER (WHERE fr.team = 'blue' AND gc.trial_vote = ft.id) >
COUNT(gc.id) FILTER (WHERE fr.team = 'red' AND gc.trial_vote = ft.id) COUNT(gc.id) FILTER (WHERE fr.team = 'red' AND gc.trial_vote = ft.id)
@@ -236,7 +257,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(trial.Locale) bf.WriteUint16(trial.Locale)
bf.WriteUint16(trial.Reward) bf.WriteUint16(trial.Reward)
bf.WriteInt16(FestivalColorCodes[trial.Monopoly]) bf.WriteInt16(FestivalColorCodes[trial.Monopoly])
if _config.ErupeConfig.ClientID >= _config.F4 { // Not in S6.0 if config.GetConfig().ClientID >= config.F4 { // Not in S6.0
bf.WriteUint16(trial.Unk) bf.WriteUint16(trial.Unk)
} }
} }
@@ -279,19 +300,19 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(reward.Quantity) bf.WriteUint16(reward.Quantity)
bf.WriteUint16(reward.ItemID) bf.WriteUint16(reward.ItemID)
// Not confirmed to be G1 but exists in G3 // Not confirmed to be G1 but exists in G3
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
bf.WriteUint16(reward.Unk5) bf.WriteUint16(reward.Unk5)
bf.WriteUint16(reward.Unk6) bf.WriteUint16(reward.Unk6)
bf.WriteUint8(reward.Unk7) bf.WriteUint8(reward.Unk7)
} }
} }
if _config.ErupeConfig.ClientID <= _config.G61 { if config.GetConfig().ClientID <= config.G61 {
if s.server.erupeConfig.GameplayOptions.MaximumFP > 0xFFFF { if config.GetConfig().GameplayOptions.MaximumFP > 0xFFFF {
s.server.erupeConfig.GameplayOptions.MaximumFP = 0xFFFF config.GetConfig().GameplayOptions.MaximumFP = 0xFFFF
} }
bf.WriteUint16(uint16(s.server.erupeConfig.GameplayOptions.MaximumFP)) bf.WriteUint16(uint16(config.GetConfig().GameplayOptions.MaximumFP))
} else { } else {
bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MaximumFP) bf.WriteUint32(config.GetConfig().GameplayOptions.MaximumFP)
} }
bf.WriteUint16(100) // Reward multiplier (%) bf.WriteUint16(100) // Reward multiplier (%)
@@ -301,7 +322,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
var guildID uint32 var guildID uint32
var guildName string var guildName string
var guildTeam = FestivalColorNone var guildTeam = FestivalColorNone
s.server.db.QueryRow(` database.QueryRow(`
SELECT fs.guild_id, g.name, fr.team, SUM(fs.souls) as _ SELECT fs.guild_id, g.name, fr.team, SUM(fs.souls) as _
FROM festa_submissions fs FROM festa_submissions fs
LEFT JOIN festa_registrations fr ON fs.guild_id = fr.guild_id LEFT JOIN festa_registrations fr ON fs.guild_id = fr.guild_id
@@ -321,7 +342,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
var guildName string var guildName string
var guildTeam = FestivalColorNone var guildTeam = FestivalColorNone
offset := 86400 * uint32(i) offset := 86400 * uint32(i)
s.server.db.QueryRow(` database.QueryRow(`
SELECT fs.guild_id, g.name, fr.team, SUM(fs.souls) as _ SELECT fs.guild_id, g.name, fr.team, SUM(fs.souls) as _
FROM festa_submissions fs FROM festa_submissions fs
LEFT JOIN festa_registrations fr ON fs.guild_id = fr.guild_id LEFT JOIN festa_registrations fr ON fs.guild_id = fr.guild_id
@@ -348,27 +369,31 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(100) // Normal rate bf.WriteUint16(100) // Normal rate
bf.WriteUint16(50) // 50% penalty bf.WriteUint16(50) // 50% penalty
if _config.ErupeConfig.ClientID >= _config.G52 { if config.GetConfig().ClientID >= config.G52 {
ps.Uint16(bf, "", false) ps.Uint16(bf, "", false)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
// state festa (U)ser // state festa (U)ser
func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfStateFestaU) pkt := p.(*mhfpacket.MsgMhfStateFestaU)
guild, err := GetGuildInfoByCharacterId(s, s.charID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
guild, err := GetGuildInfoByCharacterId(s, s.CharID)
applicant := false applicant := false
if guild != nil { if guild != nil {
applicant, _ = guild.HasApplicationForCharID(s, s.charID) applicant, _ = guild.HasApplicationForCharID(s, s.CharID)
} }
if err != nil || guild == nil || applicant { if err != nil || guild == nil || applicant {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
var souls, exists uint32 var souls, exists uint32
s.server.db.QueryRow(`SELECT COALESCE((SELECT SUM(souls) FROM festa_submissions WHERE character_id=$1), 0)`, s.charID).Scan(&souls) database.QueryRow(`SELECT COALESCE((SELECT SUM(souls) FROM festa_submissions WHERE character_id=$1), 0)`, s.CharID).Scan(&souls)
err = s.server.db.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.charID).Scan(&exists) err = database.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.CharID).Scan(&exists)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(souls) bf.WriteUint32(souls)
if err != nil { if err != nil {
@@ -378,16 +403,16 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
bf.WriteBool(false) bf.WriteBool(false)
bf.WriteBool(true) bf.WriteBool(true)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
// state festa (G)uild // state festa (G)uild
func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfStateFestaG) pkt := p.(*mhfpacket.MsgMhfStateFestaG)
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.CharID)
applicant := false applicant := false
if guild != nil { if guild != nil {
applicant, _ = guild.HasApplicationForCharID(s, s.charID) applicant, _ = guild.HasApplicationForCharID(s, s.CharID)
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
if err != nil || guild == nil || applicant { if err != nil || guild == nil || applicant {
@@ -396,7 +421,7 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
resp.WriteInt32(-1) resp.WriteInt32(-1)
resp.WriteInt32(0) resp.WriteInt32(0)
resp.WriteInt32(0) resp.WriteInt32(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
return return
} }
resp.WriteUint32(guild.Souls) resp.WriteUint32(guild.Souls)
@@ -404,19 +429,19 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
resp.WriteInt32(1) // unk, rank? resp.WriteInt32(1) // unk, rank?
resp.WriteInt32(1) // unk resp.WriteInt32(1) // unk
resp.WriteInt32(1) // unk resp.WriteInt32(1) // unk
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaMember) pkt := p.(*mhfpacket.MsgMhfEnumerateFestaMember)
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil || guild == nil { if err != nil || guild == nil {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
members, err := GetGuildMembers(s, guild.ID, false) members, err := GetGuildMembers(s, guild.ID, false)
if err != nil { if err != nil {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
sort.Slice(members, func(i, j int) bool { sort.Slice(members, func(i, j int) bool {
@@ -433,70 +458,94 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
for _, member := range validMembers { for _, member := range validMembers {
bf.WriteUint32(member.CharID) bf.WriteUint32(member.CharID)
if _config.ErupeConfig.ClientID <= _config.Z1 { if config.GetConfig().ClientID <= config.Z1 {
bf.WriteUint16(uint16(member.Souls)) bf.WriteUint16(uint16(member.Souls))
bf.WriteUint16(0) bf.WriteUint16(0)
} else { } else {
bf.WriteUint32(member.Souls) bf.WriteUint32(member.Souls)
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfVoteFesta) pkt := p.(*mhfpacket.MsgMhfVoteFesta)
s.server.db.Exec(`UPDATE guild_characters SET trial_vote=$1 WHERE character_id=$2`, pkt.TrialID, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`UPDATE guild_characters SET trial_vote=$1 WHERE character_id=$2`, pkt.TrialID, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEntryFesta) pkt := p.(*mhfpacket.MsgMhfEntryFesta)
guild, err := GetGuildInfoByCharacterId(s, s.charID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
guild, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil || guild == nil { if err != nil || guild == nil {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
team := uint32(token.RNG.Intn(2)) team := uint32(token.RNG.Intn(2))
switch team { switch team {
case 0: case 0:
s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID) database.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID)
case 1: case 1:
s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'red')", guild.ID) database.Exec("INSERT INTO festa_registrations VALUES ($1, 'red')", guild.ID)
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(team) bf.WriteUint32(team)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfChargeFesta) pkt := p.(*mhfpacket.MsgMhfChargeFesta)
tx, _ := s.server.db.Begin() database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
tx, _ := database.Begin()
for i := range pkt.Souls { for i := range pkt.Souls {
if pkt.Souls[i] == 0 { if pkt.Souls[i] == 0 {
continue continue
} }
_, _ = tx.Exec(`INSERT INTO festa_submissions VALUES ($1, $2, $3, $4, now())`, s.charID, pkt.GuildID, i, pkt.Souls[i]) _, _ = tx.Exec(`INSERT INTO festa_submissions VALUES ($1, $2, $3, $4, now())`, s.CharID, pkt.GuildID, i, pkt.Souls[i])
} }
_ = tx.Commit() _ = tx.Commit()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFesta) pkt := p.(*mhfpacket.MsgMhfAcquireFesta)
s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFestaPersonalPrize) pkt := p.(*mhfpacket.MsgMhfAcquireFestaPersonalPrize)
s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfAcquireFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFestaIntermediatePrize) pkt := p.(*mhfpacket.MsgMhfAcquireFestaIntermediatePrize)
s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type Prize struct { type Prize struct {
@@ -510,7 +559,11 @@ type Prize struct {
func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaPersonalPrize) pkt := p.(*mhfpacket.MsgMhfEnumerateFestaPersonalPrize)
rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='personal'`, s.charID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, _ := database.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='personal'`, s.CharID)
var count uint32 var count uint32
prizeData := byteframe.NewByteFrame() prizeData := byteframe.NewByteFrame()
for rows.Next() { for rows.Next() {
@@ -531,12 +584,16 @@ func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(count) bf.WriteUint32(count)
bf.WriteBytes(prizeData.Data()) bf.WriteBytes(prizeData.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaIntermediatePrize) pkt := p.(*mhfpacket.MsgMhfEnumerateFestaIntermediatePrize)
rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='guild'`, s.charID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, _ := database.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='guild'`, s.CharID)
var count uint32 var count uint32
prizeData := byteframe.NewByteFrame() prizeData := byteframe.NewByteFrame()
for rows.Next() { for rows.Next() {
@@ -557,5 +614,5 @@ func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPack
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(count) bf.WriteUint32(count)
bf.WriteBytes(prizeData.Data()) bf.WriteBytes(prizeData.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,12 @@
package channelserver package channelserver
import ( import (
"fmt"
"time" "time"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
@@ -20,13 +22,17 @@ type GuildAdventure struct {
CollectedBy string `db:"collected_by"` CollectedBy string `db:"collected_by"`
} }
func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadGuildAdventure) pkt := p.(*mhfpacket.MsgMhfLoadGuildAdventure)
guild, _ := GetGuildInfoByCharacterId(s, s.charID) database, err := db.GetDB()
data, err := s.server.db.Queryx("SELECT id, destination, charge, depart, return, collected_by FROM guild_adventures WHERE guild_id = $1", guild.ID)
if err != nil { if err != nil {
s.logger.Error("Failed to get guild adventures from db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) }
guild, _ := GetGuildInfoByCharacterId(s, s.CharID)
data, err := database.Queryx("SELECT id, destination, charge, depart, return, collected_by FROM guild_adventures WHERE guild_id = $1", guild.ID)
if err != nil {
s.Logger.Error("Failed to get guild adventures from db", zap.Error(err))
DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
temp := byteframe.NewByteFrame() temp := byteframe.NewByteFrame()
@@ -43,55 +49,71 @@ func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
temp.WriteUint32(adventureData.Charge) temp.WriteUint32(adventureData.Charge)
temp.WriteUint32(adventureData.Depart) temp.WriteUint32(adventureData.Depart)
temp.WriteUint32(adventureData.Return) temp.WriteUint32(adventureData.Return)
temp.WriteBool(stringsupport.CSVContains(adventureData.CollectedBy, int(s.charID))) temp.WriteBool(stringsupport.CSVContains(adventureData.CollectedBy, int(s.CharID)))
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint8(uint8(count)) bf.WriteUint8(uint8(count))
bf.WriteBytes(temp.Data()) bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventure) pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventure)
guild, _ := GetGuildInfoByCharacterId(s, s.charID) database, err := db.GetDB()
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, gametime.TimeAdjusted().Unix(), gametime.TimeAdjusted().Add(6*time.Hour).Unix())
if err != nil { if err != nil {
s.logger.Error("Failed to register guild adventure", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) guild, _ := GetGuildInfoByCharacterId(s, s.CharID)
_, err = database.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, gametime.TimeAdjusted().Unix(), gametime.TimeAdjusted().Add(6*time.Hour).Unix())
if err != nil {
s.Logger.Error("Failed to register guild adventure", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfAcquireGuildAdventure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfAcquireGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireGuildAdventure) pkt := p.(*mhfpacket.MsgMhfAcquireGuildAdventure)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var collectedBy string var collectedBy string
err := s.server.db.QueryRow("SELECT collected_by FROM guild_adventures WHERE id = $1", pkt.ID).Scan(&collectedBy) err = database.QueryRow("SELECT collected_by FROM guild_adventures WHERE id = $1", pkt.ID).Scan(&collectedBy)
if err != nil { if err != nil {
s.logger.Error("Error parsing adventure collected by", zap.Error(err)) s.Logger.Error("Error parsing adventure collected by", zap.Error(err))
} else { } else {
collectedBy = stringsupport.CSVAdd(collectedBy, int(s.charID)) collectedBy = stringsupport.CSVAdd(collectedBy, int(s.CharID))
_, err := s.server.db.Exec("UPDATE guild_adventures SET collected_by = $1 WHERE id = $2", collectedBy, pkt.ID) _, err := database.Exec("UPDATE guild_adventures SET collected_by = $1 WHERE id = $2", collectedBy, pkt.ID)
if err != nil { if err != nil {
s.logger.Error("Failed to collect adventure in db", zap.Error(err)) s.Logger.Error("Failed to collect adventure in db", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfChargeGuildAdventure) pkt := p.(*mhfpacket.MsgMhfChargeGuildAdventure)
_, err := s.server.db.Exec("UPDATE guild_adventures SET charge = charge + $1 WHERE id = $2", pkt.Amount, pkt.ID) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to charge guild adventure", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) _, err = database.Exec("UPDATE guild_adventures SET charge = charge + $1 WHERE id = $2", pkt.Amount, pkt.ID)
if err != nil {
s.Logger.Error("Failed to charge guild adventure", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva) pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva)
guild, _ := GetGuildInfoByCharacterId(s, s.charID) database, err := db.GetDB()
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, charge, depart, return) VALUES ($1, $2, $3, $4, $5)", guild.ID, pkt.Destination, pkt.Charge, gametime.TimeAdjusted().Unix(), gametime.TimeAdjusted().Add(1*time.Hour).Unix())
if err != nil { if err != nil {
s.logger.Error("Failed to register guild adventure", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) guild, _ := GetGuildInfoByCharacterId(s, s.CharID)
_, err = database.Exec("INSERT INTO guild_adventures (guild_id, destination, charge, depart, return) VALUES ($1, $2, $3, $4, $5)", guild.ID, pkt.Destination, pkt.Charge, gametime.TimeAdjusted().Unix(), gametime.TimeAdjusted().Add(1*time.Hour).Unix())
if err != nil {
s.Logger.Error("Failed to register guild adventure", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -2,6 +2,7 @@ package channelserver
import ( import (
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"fmt" "fmt"
"time" "time"
@@ -45,12 +46,16 @@ type GuildAlliance struct {
} }
func GetAllianceData(s *Session, AllianceID uint32) (*GuildAlliance, error) { func GetAllianceData(s *Session, AllianceID uint32) (*GuildAlliance, error) {
rows, err := s.server.db.Queryx(fmt.Sprintf(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(fmt.Sprintf(`
%s %s
WHERE ga.id = $1 WHERE ga.id = $1
`, allianceInfoSelectQuery), AllianceID) `, allianceInfoSelectQuery), AllianceID)
if err != nil { if err != nil {
s.logger.Error("Failed to retrieve alliance data from database", zap.Error(err)) s.Logger.Error("Failed to retrieve alliance data from database", zap.Error(err))
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
@@ -68,13 +73,13 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
err = result.StructScan(alliance) err = result.StructScan(alliance)
if err != nil { if err != nil {
s.logger.Error("failed to retrieve alliance from database", zap.Error(err)) s.Logger.Error("failed to retrieve alliance from database", zap.Error(err))
return nil, err return nil, err
} }
parentGuild, err := GetGuildInfoByID(s, alliance.ParentGuildID) parentGuild, err := GetGuildInfoByID(s, alliance.ParentGuildID)
if err != nil { if err != nil {
s.logger.Error("Failed to get parent guild info", zap.Error(err)) s.Logger.Error("Failed to get parent guild info", zap.Error(err))
return nil, err return nil, err
} else { } else {
alliance.ParentGuild = *parentGuild alliance.ParentGuild = *parentGuild
@@ -84,7 +89,7 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
if alliance.SubGuild1ID > 0 { if alliance.SubGuild1ID > 0 {
subGuild1, err := GetGuildInfoByID(s, alliance.SubGuild1ID) subGuild1, err := GetGuildInfoByID(s, alliance.SubGuild1ID)
if err != nil { if err != nil {
s.logger.Error("Failed to get sub guild 1 info", zap.Error(err)) s.Logger.Error("Failed to get sub guild 1 info", zap.Error(err))
return nil, err return nil, err
} else { } else {
alliance.SubGuild1 = *subGuild1 alliance.SubGuild1 = *subGuild1
@@ -95,7 +100,7 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
if alliance.SubGuild2ID > 0 { if alliance.SubGuild2ID > 0 {
subGuild2, err := GetGuildInfoByID(s, alliance.SubGuild2ID) subGuild2, err := GetGuildInfoByID(s, alliance.SubGuild2ID)
if err != nil { if err != nil {
s.logger.Error("Failed to get sub guild 2 info", zap.Error(err)) s.Logger.Error("Failed to get sub guild 2 info", zap.Error(err))
return nil, err return nil, err
} else { } else {
alliance.SubGuild2 = *subGuild2 alliance.SubGuild2 = *subGuild2
@@ -106,92 +111,99 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
return alliance, nil return alliance, nil
} }
func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCreateJoint) pkt := p.(*mhfpacket.MsgMhfCreateJoint)
_, err := s.server.db.Exec("INSERT INTO guild_alliances (name, parent_id) VALUES ($1, $2)", pkt.Name, pkt.GuildID) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to create guild alliance in db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x01, 0x01, 0x01}) _, err = database.Exec("INSERT INTO guild_alliances (name, parent_id) VALUES ($1, $2)", pkt.Name, pkt.GuildID)
if err != nil {
s.Logger.Error("Failed to create guild alliance in db", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x01, 0x01, 0x01})
} }
func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOperateJoint) pkt := p.(*mhfpacket.MsgMhfOperateJoint)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
guild, err := GetGuildInfoByID(s, pkt.GuildID) guild, err := GetGuildInfoByID(s, pkt.GuildID)
if err != nil { if err != nil {
s.logger.Error("Failed to get guild info", zap.Error(err)) s.Logger.Error("Failed to get guild info", zap.Error(err))
} }
alliance, err := GetAllianceData(s, pkt.AllianceID) alliance, err := GetAllianceData(s, pkt.AllianceID)
if err != nil { if err != nil {
s.logger.Error("Failed to get alliance info", zap.Error(err)) s.Logger.Error("Failed to get alliance info", zap.Error(err))
} }
switch pkt.Action { switch pkt.Action {
case mhfpacket.OPERATE_JOINT_DISBAND: case mhfpacket.OPERATE_JOINT_DISBAND:
if guild.LeaderCharID == s.charID && alliance.ParentGuildID == guild.ID { if guild.LeaderCharID == s.CharID && alliance.ParentGuildID == guild.ID {
_, err = s.server.db.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID) _, err = database.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID)
if err != nil { if err != nil {
s.logger.Error("Failed to disband alliance", zap.Error(err)) s.Logger.Error("Failed to disband alliance", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
s.logger.Warn( s.Logger.Warn(
"Non-owner of alliance attempted disband", "Non-owner of alliance attempted disband",
zap.Uint32("CharID", s.charID), zap.Uint32("CharID", s.CharID),
zap.Uint32("AllyID", alliance.ID), zap.Uint32("AllyID", alliance.ID),
) )
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} }
case mhfpacket.OPERATE_JOINT_LEAVE: case mhfpacket.OPERATE_JOINT_LEAVE:
if guild.LeaderCharID == s.charID { if guild.LeaderCharID == s.CharID {
if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 { if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID) database.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
} else if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 { } else if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID) database.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
} else { } else {
s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID) database.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
} }
// TODO: Handle deleting Alliance applications // TODO: Handle deleting Alliance applications
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
s.logger.Warn( s.Logger.Warn(
"Non-owner of guild attempted alliance leave", "Non-owner of guild attempted alliance leave",
zap.Uint32("CharID", s.charID), zap.Uint32("CharID", s.CharID),
) )
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} }
case mhfpacket.OPERATE_JOINT_KICK: case mhfpacket.OPERATE_JOINT_KICK:
if alliance.ParentGuild.LeaderCharID == s.charID { if alliance.ParentGuild.LeaderCharID == s.CharID {
kickedGuildID := pkt.Data1.ReadUint32() kickedGuildID := pkt.Data1.ReadUint32()
if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 { if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID) database.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID)
} else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 { } else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 {
s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID) database.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID)
} else { } else {
s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID) database.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
s.logger.Warn( s.Logger.Warn(
"Non-owner of alliance attempted kick", "Non-owner of alliance attempted kick",
zap.Uint32("CharID", s.charID), zap.Uint32("CharID", s.CharID),
zap.Uint32("AllyID", alliance.ID), zap.Uint32("AllyID", alliance.ID),
) )
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} }
default: default:
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action)) panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action))
} }
} }
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfInfoJoint) pkt := p.(*mhfpacket.MsgMhfInfoJoint)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
alliance, err := GetAllianceData(s, pkt.AllianceID) alliance, err := GetAllianceData(s, pkt.AllianceID)
if err != nil { if err != nil {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
bf.WriteUint32(alliance.ID) bf.WriteUint32(alliance.ID)
bf.WriteUint32(uint32(alliance.CreatedAt.Unix())) bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
@@ -229,6 +241,6 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
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)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
} }

View File

@@ -1,6 +1,7 @@
package channelserver package channelserver
import ( import (
"erupe-ce/utils/db"
"fmt" "fmt"
"time" "time"
@@ -46,10 +47,14 @@ func (gm *GuildMember) IsSubLeader() bool {
} }
func (gm *GuildMember) Save(s *Session) error { func (gm *GuildMember) Save(s *Session) error {
_, err := s.server.db.Exec("UPDATE guild_characters SET avoid_leadership=$1, order_index=$2 WHERE character_id=$3", gm.AvoidLeadership, gm.OrderIndex, gm.CharID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
_, err = database.Exec("UPDATE guild_characters SET avoid_leadership=$1, order_index=$2 WHERE character_id=$3", gm.AvoidLeadership, gm.OrderIndex, gm.CharID)
if err != nil { if err != nil {
s.logger.Error( s.Logger.Error(
"failed to update guild member data", "failed to update guild member data",
zap.Error(err), zap.Error(err),
zap.Uint32("charID", gm.CharID), zap.Uint32("charID", gm.CharID),
@@ -87,13 +92,17 @@ SELECT * FROM (
` `
func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMember, error) { func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMember, error) {
rows, err := s.server.db.Queryx(fmt.Sprintf(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(fmt.Sprintf(`
%s %s
WHERE guild_id = $1 AND is_applicant = $2 WHERE guild_id = $1 AND is_applicant = $2
`, guildMembersSelectSQL), guildID, applicants) `, guildMembersSelectSQL), guildID, applicants)
if err != nil { if err != nil {
s.logger.Error("failed to retrieve membership data for guild", zap.Error(err), zap.Uint32("guildID", guildID)) s.Logger.Error("failed to retrieve membership data for guild", zap.Error(err), zap.Uint32("guildID", guildID))
return nil, err return nil, err
} }
@@ -115,10 +124,15 @@ func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMembe
} }
func GetCharacterGuildData(s *Session, charID uint32) (*GuildMember, error) { func GetCharacterGuildData(s *Session, charID uint32) (*GuildMember, error) {
rows, err := s.server.db.Queryx(fmt.Sprintf("%s WHERE character_id=$1", guildMembersSelectSQL), charID)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(fmt.Sprintf("%s WHERE character_id=$1", guildMembersSelectSQL), charID)
if err != nil { if err != nil {
s.logger.Error(fmt.Sprintf("failed to retrieve membership data for character '%d'", charID)) s.Logger.Error(fmt.Sprintf("failed to retrieve membership data for character '%d'", charID))
return nil, err return nil, err
} }
@@ -139,7 +153,7 @@ func buildGuildMemberObjectFromDBResult(rows *sqlx.Rows, err error, s *Session)
err = rows.StructScan(&memberData) err = rows.StructScan(&memberData)
if err != nil { if err != nil {
s.logger.Error("failed to retrieve guild data from database", zap.Error(err)) s.Logger.Error("failed to retrieve guild data from database", zap.Error(err))
return nil, err return nil, err
} }

View File

@@ -3,6 +3,7 @@ package channelserver
import ( import (
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt" "fmt"
@@ -11,41 +12,44 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostGuildScout) pkt := p.(*mhfpacket.MsgMhfPostGuildScout)
actorCharGuildData, err := GetCharacterGuildData(s, s.charID) actorCharGuildData, err := GetCharacterGuildData(s, s.CharID)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
panic(err) panic(err)
} }
if actorCharGuildData == nil || !actorCharGuildData.CanRecruit() { if actorCharGuildData == nil || !actorCharGuildData.CanRecruit() {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
guildInfo, err := GetGuildInfoByID(s, actorCharGuildData.GuildID) guildInfo, err := GetGuildInfoByID(s, actorCharGuildData.GuildID)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
panic(err) panic(err)
} }
hasApplication, err := guildInfo.HasApplicationForCharID(s, pkt.CharID) hasApplication, err := guildInfo.HasApplicationForCharID(s, pkt.CharID)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
panic(err) panic(err)
} }
if hasApplication { if hasApplication {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x04}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x04})
return return
} }
database, err := db.GetDB()
transaction, err := s.server.db.Begin() if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
transaction, err := database.Begin()
if err != nil { if err != nil {
panic(err) panic(err)
@@ -55,16 +59,16 @@ func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
if err != nil { if err != nil {
rollbackTransaction(s, transaction) rollbackTransaction(s, transaction)
doAckBufFail(s, pkt.AckHandle, nil) DoAckBufFail(s, pkt.AckHandle, nil)
panic(err) panic(err)
} }
mail := &Mail{ mail := &Mail{
SenderID: s.charID, SenderID: s.CharID,
RecipientID: pkt.CharID, RecipientID: pkt.CharID,
Subject: s.server.i18n.guild.invite.title, Subject: s.Server.i18n.guild.invite.title,
Body: fmt.Sprintf( Body: fmt.Sprintf(
s.server.i18n.guild.invite.body, s.Server.i18n.guild.invite.body,
guildInfo.Name, guildInfo.Name,
), ),
IsGuildInvite: true, IsGuildInvite: true,
@@ -74,52 +78,52 @@ func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
if err != nil { if err != nil {
rollbackTransaction(s, transaction) rollbackTransaction(s, transaction)
doAckBufFail(s, pkt.AckHandle, nil) DoAckBufFail(s, pkt.AckHandle, nil)
return return
} }
err = transaction.Commit() err = transaction.Commit()
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, nil) DoAckBufFail(s, pkt.AckHandle, nil)
panic(err) panic(err)
} }
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCancelGuildScout) pkt := p.(*mhfpacket.MsgMhfCancelGuildScout)
guildCharData, err := GetCharacterGuildData(s, s.charID) guildCharData, err := GetCharacterGuildData(s, s.CharID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
if guildCharData == nil || !guildCharData.CanRecruit() { if guildCharData == nil || !guildCharData.CanRecruit() {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
guild, err := GetGuildInfoByID(s, guildCharData.GuildID) guild, err := GetGuildInfoByID(s, guildCharData.GuildID)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
err = guild.CancelInvitation(s, pkt.InvitationID) err = guild.CancelInvitation(s, pkt.InvitationID)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAnswerGuildScout) pkt := p.(*mhfpacket.MsgMhfAnswerGuildScout)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
guild, err := GetGuildInfoByCharacterId(s, pkt.LeaderID) guild, err := GetGuildInfoByCharacterId(s, pkt.LeaderID)
@@ -128,84 +132,87 @@ func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {
panic(err) panic(err)
} }
app, err := guild.GetApplicationForCharID(s, s.charID, GuildApplicationTypeInvited) app, err := guild.GetApplicationForCharID(s, s.CharID, GuildApplicationTypeInvited)
if app == nil || err != nil { if app == nil || err != nil {
s.logger.Warn( s.Logger.Warn(
"Guild invite missing, deleted?", "Guild invite missing, deleted?",
zap.Error(err), zap.Error(err),
zap.Uint32("guildID", guild.ID), zap.Uint32("guildID", guild.ID),
zap.Uint32("charID", s.charID), zap.Uint32("charID", s.CharID),
) )
bf.WriteUint32(7) bf.WriteUint32(7)
bf.WriteUint32(guild.ID) bf.WriteUint32(guild.ID)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
return return
} }
var mail []Mail var mail []Mail
if pkt.Answer { if pkt.Answer {
err = guild.AcceptApplication(s, s.charID) err = guild.AcceptApplication(s, s.CharID)
mail = append(mail, Mail{ mail = append(mail, Mail{
RecipientID: s.charID, RecipientID: s.CharID,
Subject: s.server.i18n.guild.invite.success.title, Subject: s.Server.i18n.guild.invite.success.title,
Body: fmt.Sprintf(s.server.i18n.guild.invite.success.body, guild.Name), Body: fmt.Sprintf(s.Server.i18n.guild.invite.success.body, guild.Name),
IsSystemMessage: true, IsSystemMessage: true,
}) })
mail = append(mail, Mail{ mail = append(mail, Mail{
SenderID: s.charID, SenderID: s.CharID,
RecipientID: pkt.LeaderID, RecipientID: pkt.LeaderID,
Subject: s.server.i18n.guild.invite.accepted.title, Subject: s.Server.i18n.guild.invite.accepted.title,
Body: fmt.Sprintf(s.server.i18n.guild.invite.accepted.body, guild.Name), Body: fmt.Sprintf(s.Server.i18n.guild.invite.accepted.body, guild.Name),
IsSystemMessage: true, IsSystemMessage: true,
}) })
} else { } else {
err = guild.RejectApplication(s, s.charID) err = guild.RejectApplication(s, s.CharID)
mail = append(mail, Mail{ mail = append(mail, Mail{
RecipientID: s.charID, RecipientID: s.CharID,
Subject: s.server.i18n.guild.invite.rejected.title, Subject: s.Server.i18n.guild.invite.rejected.title,
Body: fmt.Sprintf(s.server.i18n.guild.invite.rejected.body, guild.Name), Body: fmt.Sprintf(s.Server.i18n.guild.invite.rejected.body, guild.Name),
IsSystemMessage: true, IsSystemMessage: true,
}) })
mail = append(mail, Mail{ mail = append(mail, Mail{
SenderID: s.charID, SenderID: s.CharID,
RecipientID: pkt.LeaderID, RecipientID: pkt.LeaderID,
Subject: s.server.i18n.guild.invite.declined.title, Subject: s.Server.i18n.guild.invite.declined.title,
Body: fmt.Sprintf(s.server.i18n.guild.invite.declined.body, guild.Name), Body: fmt.Sprintf(s.Server.i18n.guild.invite.declined.body, guild.Name),
IsSystemMessage: true, IsSystemMessage: true,
}) })
} }
if err != nil { if err != nil {
bf.WriteUint32(7) bf.WriteUint32(7)
bf.WriteUint32(guild.ID) bf.WriteUint32(guild.ID)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteUint32(guild.ID) bf.WriteUint32(guild.ID)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
for _, m := range mail { for _, m := range mail {
m.Send(s, nil) m.Send(s, nil)
} }
} }
} }
func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGuildScoutList) pkt := p.(*mhfpacket.MsgMhfGetGuildScoutList)
guildInfo, err := GetGuildInfoByCharacterId(s, s.charID) guildInfo, err := GetGuildInfoByCharacterId(s, s.CharID)
if guildInfo == nil && s.prevGuildID == 0 { if guildInfo == nil && s.prevGuildID == 0 {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} else { } else {
guildInfo, err = GetGuildInfoByID(s, s.prevGuildID) guildInfo, err = GetGuildInfoByID(s, s.prevGuildID)
if guildInfo == nil || err != nil { if guildInfo == nil || err != nil {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
database, err := db.GetDB()
rows, err := s.server.db.Queryx(` if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`
SELECT c.id, c.name, c.hr, c.gr, ga.actor_id SELECT c.id, c.name, c.hr, c.gr, ga.actor_id
FROM guild_applications ga FROM guild_applications ga
JOIN characters c ON c.id = ga.character_id JOIN characters c ON c.id = ga.character_id
@@ -213,8 +220,8 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
`, guildInfo.ID) `, guildInfo.ID)
if err != nil { if err != nil {
s.logger.Error("failed to retrieve scouted characters", zap.Error(err)) s.Logger.Error("failed to retrieve scouted characters", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
@@ -237,7 +244,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
err = rows.Scan(&charID, &charName, &HR, &GR, &actorID) err = rows.Scan(&charID, &charName, &HR, &GR, &actorID)
if err != nil { if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil) DoAckSimpleFail(s, pkt.AckHandle, nil)
continue continue
} }
@@ -262,25 +269,28 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(count) bf.WriteUint32(count)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRejectGuildScout) pkt := p.(*mhfpacket.MsgMhfGetRejectGuildScout)
database, err := db.GetDB()
row := s.server.db.QueryRow("SELECT restrict_guild_scout FROM characters WHERE id=$1", s.charID) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
row := database.QueryRow("SELECT restrict_guild_scout FROM characters WHERE id=$1", s.CharID)
var currentStatus bool var currentStatus bool
err := row.Scan(&currentStatus) err = row.Scan(&currentStatus)
if err != nil { if err != nil {
s.logger.Error( s.Logger.Error(
"failed to retrieve character guild scout status", "failed to retrieve character guild scout status",
zap.Error(err), zap.Error(err),
zap.Uint32("charID", s.charID), zap.Uint32("charID", s.CharID),
) )
doAckSimpleFail(s, pkt.AckHandle, nil) DoAckSimpleFail(s, pkt.AckHandle, nil)
return return
} }
@@ -290,23 +300,26 @@ func handleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
response = 0x01 response = 0x01
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, response}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, response})
} }
func handleMsgMhfSetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfSetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSetRejectGuildScout) pkt := p.(*mhfpacket.MsgMhfSetRejectGuildScout)
database, err := db.GetDB()
_, err := s.server.db.Exec("UPDATE characters SET restrict_guild_scout=$1 WHERE id=$2", pkt.Reject, s.charID) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
_, err = database.Exec("UPDATE characters SET restrict_guild_scout=$1 WHERE id=$2", pkt.Reject, s.CharID)
if err != nil { if err != nil {
s.logger.Error( s.Logger.Error(
"failed to update character guild scout status", "failed to update character guild scout status",
zap.Error(err), zap.Error(err),
zap.Uint32("charID", s.charID), zap.Uint32("charID", s.CharID),
) )
doAckSimpleFail(s, pkt.AckHandle, nil) DoAckSimpleFail(s, pkt.AckHandle, nil)
return return
} }
doAckSimpleSucceed(s, pkt.AckHandle, nil) DoAckSimpleSucceed(s, pkt.AckHandle, nil)
} }

View File

@@ -1,10 +1,13 @@
package channelserver package channelserver
import ( import (
"erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt"
"time" "time"
) )
@@ -21,24 +24,27 @@ type TreasureHunt struct {
Claimed bool `db:"claimed"` Claimed bool `db:"claimed"`
} }
func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildTresure) pkt := p.(*mhfpacket.MsgMhfEnumerateGuildTresure)
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil || guild == nil { if err != nil || guild == nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
var hunts []TreasureHunt var hunts []TreasureHunt
var hunt TreasureHunt var hunt TreasureHunt
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch pkt.MaxHunts { switch pkt.MaxHunts {
case 1: case 1:
err = s.server.db.QueryRowx(`SELECT id, host_id, destination, level, start, hunt_data FROM guild_hunts WHERE host_id=$1 AND acquired=FALSE`, s.charID).StructScan(&hunt) err = database.QueryRowx(`SELECT id, host_id, destination, level, start, hunt_data FROM guild_hunts WHERE host_id=$1 AND acquired=FALSE`, s.CharID).StructScan(&hunt)
if err == nil { if err == nil {
hunts = append(hunts, hunt) hunts = append(hunts, hunt)
} }
case 30: case 30:
rows, err := s.server.db.Queryx(`SELECT gh.id, gh.host_id, gh.destination, gh.level, gh.start, gh.collected, gh.hunt_data, rows, err := database.Queryx(`SELECT gh.id, gh.host_id, gh.destination, gh.level, gh.start, gh.collected, gh.hunt_data,
(SELECT COUNT(*) FROM guild_characters gc WHERE gc.treasure_hunt = gh.id AND gc.character_id <> $1) AS hunters, (SELECT COUNT(*) FROM guild_characters gc WHERE gc.treasure_hunt = gh.id AND gc.character_id <> $1) AS hunters,
CASE CASE
WHEN ghc.character_id IS NOT NULL THEN true WHEN ghc.character_id IS NOT NULL THEN true
@@ -47,15 +53,15 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
FROM guild_hunts gh FROM guild_hunts gh
LEFT JOIN guild_hunts_claimed ghc ON gh.id = ghc.hunt_id AND ghc.character_id = $1 LEFT JOIN guild_hunts_claimed ghc ON gh.id = ghc.hunt_id AND ghc.character_id = $1
WHERE gh.guild_id=$2 AND gh.level=2 AND gh.acquired=TRUE WHERE gh.guild_id=$2 AND gh.level=2 AND gh.acquired=TRUE
`, s.charID, guild.ID) `, s.CharID, guild.ID)
if err != nil { if err != nil {
rows.Close() rows.Close()
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} else { } else {
for rows.Next() { for rows.Next() {
err = rows.StructScan(&hunt) err = rows.StructScan(&hunt)
if err == nil && hunt.Start.Add(time.Second*time.Duration(s.server.erupeConfig.GameplayOptions.TreasureHuntExpiry)).After(gametime.TimeAdjusted()) { if err == nil && hunt.Start.Add(time.Second*time.Duration(config.GetConfig().GameplayOptions.TreasureHuntExpiry)).After(gametime.TimeAdjusted()) {
hunts = append(hunts, hunt) hunts = append(hunts, hunt)
} }
} }
@@ -77,22 +83,22 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
bf.WriteBool(h.Claimed) bf.WriteBool(h.Claimed)
bf.WriteBytes(h.HuntData) bf.WriteBytes(h.HuntData)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfRegistGuildTresure) pkt := p.(*mhfpacket.MsgMhfRegistGuildTresure)
bf := byteframe.NewByteFrameFromBytes(pkt.Data) bf := byteframe.NewByteFrameFromBytes(pkt.Data)
huntData := byteframe.NewByteFrame() huntData := byteframe.NewByteFrame()
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil || guild == nil { if err != nil || guild == nil {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
guildCats := getGuildAirouList(s) guildCats := getGuildAirouList(s)
destination := bf.ReadUint32() destination := bf.ReadUint32()
level := bf.ReadUint32() level := bf.ReadUint32()
huntData.WriteUint32(s.charID) huntData.WriteUint32(s.CharID)
huntData.WriteBytes(stringsupport.PaddedString(s.Name, 18, true)) huntData.WriteBytes(stringsupport.PaddedString(s.Name, 18, true))
catsUsed := "" catsUsed := ""
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
@@ -109,29 +115,41 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {
huntData.WriteBytes(bf.ReadBytes(9)) huntData.WriteBytes(bf.ReadBytes(9))
} }
} }
s.server.db.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6) database, err := db.GetDB()
`, guild.ID, s.charID, destination, level, huntData.Data(), catsUsed) if err != nil {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6)
`, guild.ID, s.CharID, destination, level, huntData.Data(), catsUsed)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresure) pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresure)
s.server.db.Exec(`UPDATE guild_hunts SET acquired=true WHERE id=$1`, pkt.HuntID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`UPDATE guild_hunts SET acquired=true WHERE id=$1`, pkt.HuntID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOperateGuildTresureReport) pkt := p.(*mhfpacket.MsgMhfOperateGuildTresureReport)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch pkt.State { switch pkt.State {
case 0: // Report registration case 0: // Report registration
s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=$1 WHERE character_id=$2`, pkt.HuntID, s.charID) database.Exec(`UPDATE guild_characters SET treasure_hunt=$1 WHERE character_id=$2`, pkt.HuntID, s.CharID)
case 1: // Collected by hunter case 1: // Collected by hunter
s.server.db.Exec(`UPDATE guild_hunts SET collected=true WHERE id=$1`, pkt.HuntID) database.Exec(`UPDATE guild_hunts SET collected=true WHERE id=$1`, pkt.HuntID)
s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID) database.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID)
case 2: // Claim treasure case 2: // Claim treasure
s.server.db.Exec(`INSERT INTO guild_hunts_claimed VALUES ($1, $2)`, pkt.HuntID, s.charID) database.Exec(`INSERT INTO guild_hunts_claimed VALUES ($1, $2)`, pkt.HuntID, s.CharID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type TreasureSouvenir struct { type TreasureSouvenir struct {
@@ -139,7 +157,7 @@ type TreasureSouvenir struct {
Quantity uint32 Quantity uint32
} }
func handleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGuildTresureSouvenir) pkt := p.(*mhfpacket.MsgMhfGetGuildTresureSouvenir)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(0) bf.WriteUint32(0)
@@ -149,10 +167,10 @@ func handleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(souvenir.Destination) bf.WriteUint32(souvenir.Destination)
bf.WriteUint32(souvenir.Quantity) bf.WriteUint32(souvenir.Quantity)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfAcquireGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) { func HandleMsgMhfAcquireGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresureSouvenir) pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresureSouvenir)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -1,9 +1,10 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/mhfitem" "erupe-ce/utils/mhfitem"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
@@ -42,8 +43,12 @@ FROM warehouse
func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateInterior) pkt := p.(*mhfpacket.MsgMhfUpdateInterior)
s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type HouseData struct { type HouseData struct {
@@ -57,6 +62,10 @@ type HouseData struct {
func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) pkt := p.(*mhfpacket.MsgMhfEnumerateHouse)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(0) bf.WriteUint16(0)
var houses []HouseData var houses []HouseData
@@ -65,18 +74,18 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
switch pkt.Method { switch pkt.Method {
case 1: case 1:
var friendsList string var friendsList string
s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&friendsList) database.QueryRow("SELECT friends FROM characters WHERE id=$1", s.CharID).Scan(&friendsList)
cids := stringsupport.CSVElems(friendsList) cids := stringsupport.CSVElems(friendsList)
for _, cid := range cids { for _, cid := range cids {
house := HouseData{} house := HouseData{}
row := s.server.db.QueryRowx(houseQuery, cid) row := database.QueryRowx(houseQuery, cid)
err := row.StructScan(&house) err := row.StructScan(&house)
if err == nil { if err == nil {
houses = append(houses, house) houses = append(houses, house)
} }
} }
case 2: case 2:
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil || guild == nil { if err != nil || guild == nil {
break break
} }
@@ -86,7 +95,7 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
} }
for _, member := range guildMembers { for _, member := range guildMembers {
house := HouseData{} house := HouseData{}
row := s.server.db.QueryRowx(houseQuery, member.CharID) row := database.QueryRowx(houseQuery, member.CharID)
err = row.StructScan(&house) err = row.StructScan(&house)
if err == nil { if err == nil {
houses = append(houses, house) houses = append(houses, house)
@@ -96,7 +105,7 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
houseQuery = `SELECT c.id, hr, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password houseQuery = `SELECT c.id, hr, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password
FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE name ILIKE $1` FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE name ILIKE $1`
house := HouseData{} house := HouseData{}
rows, _ := s.server.db.Queryx(houseQuery, fmt.Sprintf(`%%%s%%`, pkt.Name)) rows, _ := database.Queryx(houseQuery, fmt.Sprintf(`%%%s%%`, pkt.Name))
for rows.Next() { for rows.Next() {
err := rows.StructScan(&house) err := rows.StructScan(&house)
if err == nil { if err == nil {
@@ -105,7 +114,7 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
} }
case 4: case 4:
house := HouseData{} house := HouseData{}
row := s.server.db.QueryRowx(houseQuery, pkt.CharID) row := database.QueryRowx(houseQuery, pkt.CharID)
err := row.StructScan(&house) err := row.StructScan(&house)
if err == nil { if err == nil {
houses = append(houses, house) houses = append(houses, house)
@@ -122,39 +131,47 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(0) bf.WriteUint8(0)
} }
bf.WriteUint16(house.HR) bf.WriteUint16(house.HR)
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
bf.WriteUint16(house.GR) bf.WriteUint16(house.GR)
} }
ps.Uint8(bf, house.Name, true) ps.Uint8(bf, house.Name, true)
} }
bf.Seek(0, 0) bf.Seek(0, 0)
bf.WriteUint16(uint16(len(houses))) bf.WriteUint16(uint16(len(houses)))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateHouse) pkt := p.(*mhfpacket.MsgMhfUpdateHouse)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
// 01 = closed // 01 = closed
// 02 = open anyone // 02 = open anyone
// 03 = open friends // 03 = open friends
// 04 = open guild // 04 = open guild
// 05 = open friends+guild // 05 = open friends+guild
s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID) database.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.CharID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadHouse) pkt := p.(*mhfpacket.MsgMhfLoadHouse)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var state uint8 var state uint8
var password string var password string
s.server.db.QueryRow(`SELECT COALESCE(house_state, 2) as house_state, COALESCE(house_password, '') as house_password FROM user_binary WHERE id=$1 database.QueryRow(`SELECT COALESCE(house_state, 2) as house_state, COALESCE(house_password, '') as house_password FROM user_binary WHERE id=$1
`, pkt.CharID).Scan(&state, &password) `, pkt.CharID).Scan(&state, &password)
if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass {
if pkt.Password != password { if pkt.Password != password {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
@@ -165,10 +182,10 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
// Friends list verification // Friends list verification
if state == 3 || state == 5 { if state == 3 || state == 5 {
var friendsList string var friendsList string
s.server.db.QueryRow(`SELECT friends FROM characters WHERE id=$1`, pkt.CharID).Scan(&friendsList) database.QueryRow(`SELECT friends FROM characters WHERE id=$1`, pkt.CharID).Scan(&friendsList)
cids := stringsupport.CSVElems(friendsList) cids := stringsupport.CSVElems(friendsList)
for _, cid := range cids { for _, cid := range cids {
if uint32(cid) == s.charID { if uint32(cid) == s.CharID {
allowed = true allowed = true
break break
} }
@@ -177,8 +194,8 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
// Guild verification // Guild verification
if state > 3 { if state > 3 {
ownGuild, err := GetGuildInfoByCharacterId(s, s.charID) ownGuild, err := GetGuildInfoByCharacterId(s, s.CharID)
isApplicant, _ := ownGuild.HasApplicationForCharID(s, s.charID) isApplicant, _ := ownGuild.HasApplicationForCharID(s, s.CharID)
if err == nil && ownGuild != nil { if err == nil && ownGuild != nil {
othersGuild, err := GetGuildInfoByCharacterId(s, pkt.CharID) othersGuild, err := GetGuildInfoByCharacterId(s, pkt.CharID)
if err == nil && othersGuild != nil { if err == nil && othersGuild != nil {
@@ -190,13 +207,13 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
} }
if !allowed { if !allowed {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte
s.server.db.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1 database.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1
`, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden) `, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden)
if houseFurniture == nil { if houseFurniture == nil {
houseFurniture = make([]byte, 20) houseFurniture = make([]byte, 20)
@@ -226,59 +243,76 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
} }
} }
if len(bf.Data()) == 0 { if len(bf.Data()) == 0 {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
} }
func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetMyhouseInfo) pkt := p.(*mhfpacket.MsgMhfGetMyhouseInfo)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var data []byte var data []byte
s.server.db.QueryRow(`SELECT mission FROM user_binary WHERE id=$1`, s.charID).Scan(&data) database.QueryRow(`SELECT mission FROM user_binary WHERE id=$1`, s.CharID).Scan(&data)
if len(data) > 0 { if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 9)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 9))
} }
} }
func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateMyhouseInfo) pkt := p.(*mhfpacket.MsgMhfUpdateMyhouseInfo)
s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Data, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Data, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadDecoMyset) pkt := p.(*mhfpacket.MsgMhfLoadDecoMyset)
var data []byte
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to load decomyset", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var data []byte
err = database.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil {
s.Logger.Error("Failed to load decomyset", zap.Error(err))
} }
if len(data) == 0 { if len(data) == 0 {
data = []byte{0x01, 0x00} data = []byte{0x01, 0x00}
if s.server.erupeConfig.ClientID < _config.G10 { if config.GetConfig().ClientID < config.G10 {
data = []byte{0x00, 0x00} data = []byte{0x00, 0x00}
} }
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveDecoMyset) pkt := p.(*mhfpacket.MsgMhfSaveDecoMyset)
var temp []byte database, err := db.GetDB()
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&temp)
if err != nil { if err != nil {
s.logger.Error("Failed to load decomyset", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) }
var temp []byte
err = database.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.CharID).Scan(&temp)
if err != nil {
s.Logger.Error("Failed to load decomyset", zap.Error(err))
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
// Version handling // Version handling
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var size uint var size uint
if s.server.erupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
size = 76 size = 76
bf.WriteUint8(1) bf.WriteUint8(1)
} else { } else {
@@ -314,8 +348,8 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
} }
dumpSaveData(s, bf.Data(), "decomyset") dumpSaveData(s, bf.Data(), "decomyset")
s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", bf.Data(), s.charID) database.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", bf.Data(), s.CharID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type Title struct { type Title struct {
@@ -326,13 +360,17 @@ type Title struct {
func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateTitle) pkt := p.(*mhfpacket.MsgMhfEnumerateTitle)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var count uint16 var count uint16
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
rows, err := s.server.db.Queryx("SELECT id, unlocked_at, updated_at FROM titles WHERE char_id=$1", s.charID) rows, err := database.Queryx("SELECT id, unlocked_at, updated_at FROM titles WHERE char_id=$1", s.CharID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
return return
} }
for rows.Next() { for rows.Next() {
@@ -349,35 +387,47 @@ func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {
} }
bf.Seek(0, io.SeekStart) bf.Seek(0, io.SeekStart)
bf.WriteUint16(count) bf.WriteUint16(count)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireTitle) pkt := p.(*mhfpacket.MsgMhfAcquireTitle)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
for _, title := range pkt.TitleIDs { for _, title := range pkt.TitleIDs {
var exists int var exists int
err := s.server.db.QueryRow(`SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2`, title, s.charID).Scan(&exists) err := database.QueryRow(`SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2`, title, s.CharID).Scan(&exists)
if err != nil || exists == 0 { if err != nil || exists == 0 {
s.server.db.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, title, s.charID) database.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, title, s.CharID)
} else { } else {
s.server.db.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, title, s.charID) database.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, title, s.CharID)
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {}
func initializeWarehouse(s *Session) { func initializeWarehouse(s *Session) {
var t int database, err := db.GetDB()
err := s.server.db.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.charID).Scan(&t)
if err != nil { if err != nil {
s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var t int
err = database.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.CharID).Scan(&t)
if err != nil {
database.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.CharID)
} }
} }
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOperateWarehouse) pkt := p.(*mhfpacket.MsgMhfOperateWarehouse)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
initializeWarehouse(s) initializeWarehouse(s)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint8(pkt.Operation) bf.WriteUint8(pkt.Operation)
@@ -386,7 +436,7 @@ func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
var count uint8 var count uint8
itemNames := make([]string, 10) itemNames := make([]string, 10)
equipNames := make([]string, 10) equipNames := make([]string, 10)
s.server.db.QueryRow(fmt.Sprintf("%s WHERE character_id=$1", warehouseNamesQuery), s.charID).Scan(&itemNames[0], database.QueryRow(fmt.Sprintf("%s WHERE character_id=$1", warehouseNamesQuery), s.CharID).Scan(&itemNames[0],
&itemNames[1], &itemNames[2], &itemNames[3], &itemNames[4], &itemNames[5], &itemNames[6], &itemNames[7], &itemNames[8], &itemNames[9], &equipNames[0], &itemNames[1], &itemNames[2], &itemNames[3], &itemNames[4], &itemNames[5], &itemNames[6], &itemNames[7], &itemNames[8], &itemNames[9], &equipNames[0],
&equipNames[1], &equipNames[2], &equipNames[3], &equipNames[4], &equipNames[5], &equipNames[6], &equipNames[7], &equipNames[8], &equipNames[9]) &equipNames[1], &equipNames[2], &equipNames[3], &equipNames[4], &equipNames[5], &equipNames[6], &equipNames[7], &equipNames[8], &equipNames[9])
bf.WriteUint32(0) bf.WriteUint32(0)
@@ -415,9 +465,9 @@ func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
case 2: case 2:
switch pkt.BoxType { switch pkt.BoxType {
case 0: case 0:
s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET item%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID) database.Exec(fmt.Sprintf("UPDATE warehouse SET item%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.CharID)
case 1: case 1:
s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET equip%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID) database.Exec(fmt.Sprintf("UPDATE warehouse SET equip%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.CharID)
} }
case 3: case 3:
bf.WriteUint32(0) // Usage renewal time, >1 = disabled bf.WriteUint32(0) // Usage renewal time, >1 = disabled
@@ -433,28 +483,40 @@ func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
// 2 = Rename // 2 = Rename
// 3 = Get usage limit // 3 = Get usage limit
// 4 = Get gift box names (doesn't do anything?) // 4 = Get gift box names (doesn't do anything?)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func addWarehouseItem(s *Session, item mhfitem.MHFItemStack) { func addWarehouseItem(s *Session, item mhfitem.MHFItemStack) {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
giftBox := warehouseGetItems(s, 10) giftBox := warehouseGetItems(s, 10)
item.WarehouseID = token.RNG.Uint32() item.WarehouseID = token.RNG.Uint32()
giftBox = append(giftBox, item) giftBox = append(giftBox, item)
s.server.db.Exec("UPDATE warehouse SET item10=$1 WHERE character_id=$2", mhfitem.SerializeWarehouseItems(giftBox), s.charID) database.Exec("UPDATE warehouse SET item10=$1 WHERE character_id=$2", mhfitem.SerializeWarehouseItems(giftBox), s.CharID)
} }
func addWarehouseEquipment(s *Session, equipment mhfitem.MHFEquipment) { func addWarehouseEquipment(s *Session, equipment mhfitem.MHFEquipment) {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
giftBox := warehouseGetEquipment(s, 10) giftBox := warehouseGetEquipment(s, 10)
equipment.WarehouseID = token.RNG.Uint32() equipment.WarehouseID = token.RNG.Uint32()
giftBox = append(giftBox, equipment) giftBox = append(giftBox, equipment)
s.server.db.Exec("UPDATE warehouse SET equip10=$1 WHERE character_id=$2", mhfitem.SerializeWarehouseEquipment(giftBox), s.charID) database.Exec("UPDATE warehouse SET equip10=$1 WHERE character_id=$2", mhfitem.SerializeWarehouseEquipment(giftBox), s.CharID)
} }
func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack { func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
initializeWarehouse(s) initializeWarehouse(s)
var data []byte var data []byte
var items []mhfitem.MHFItemStack var items []mhfitem.MHFItemStack
s.server.db.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data) database.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.CharID).Scan(&data)
if len(data) > 0 { if len(data) > 0 {
box := byteframe.NewByteFrameFromBytes(data) box := byteframe.NewByteFrameFromBytes(data)
numStacks := box.ReadUint16() numStacks := box.ReadUint16()
@@ -467,9 +529,13 @@ func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
} }
func warehouseGetEquipment(s *Session, index uint8) []mhfitem.MHFEquipment { func warehouseGetEquipment(s *Session, index uint8) []mhfitem.MHFEquipment {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var data []byte var data []byte
var equipment []mhfitem.MHFEquipment var equipment []mhfitem.MHFEquipment
s.server.db.QueryRow(fmt.Sprintf(`SELECT equip%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data) database.QueryRow(fmt.Sprintf(`SELECT equip%d FROM warehouse WHERE character_id=$1`, index), s.CharID).Scan(&data)
if len(data) > 0 { if len(data) > 0 {
box := byteframe.NewByteFrameFromBytes(data) box := byteframe.NewByteFrameFromBytes(data)
numStacks := box.ReadUint16() numStacks := box.ReadUint16()
@@ -493,18 +559,22 @@ func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {
bf.WriteBytes(mhfitem.SerializeWarehouseEquipment(equipment)) bf.WriteBytes(mhfitem.SerializeWarehouseEquipment(equipment))
} }
if bf.Index() > 0 { if bf.Index() > 0 {
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
} }
func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateWarehouse) pkt := p.(*mhfpacket.MsgMhfUpdateWarehouse)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch pkt.BoxType { switch pkt.BoxType {
case 0: case 0:
newStacks := mhfitem.DiffItemStacks(warehouseGetItems(s, pkt.BoxIndex), pkt.UpdatedItems) newStacks := mhfitem.DiffItemStacks(warehouseGetItems(s, pkt.BoxIndex), pkt.UpdatedItems)
s.server.db.Exec(fmt.Sprintf(`UPDATE warehouse SET item%d=$1 WHERE character_id=$2`, pkt.BoxIndex), mhfitem.SerializeWarehouseItems(newStacks), s.charID) database.Exec(fmt.Sprintf(`UPDATE warehouse SET item%d=$1 WHERE character_id=$2`, pkt.BoxIndex), mhfitem.SerializeWarehouseItems(newStacks), s.CharID)
case 1: case 1:
var fEquip []mhfitem.MHFEquipment var fEquip []mhfitem.MHFEquipment
oEquips := warehouseGetEquipment(s, pkt.BoxIndex) oEquips := warehouseGetEquipment(s, pkt.BoxIndex)
@@ -528,7 +598,7 @@ func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {
fEquip = append(fEquip, oEquip) fEquip = append(fEquip, oEquip)
} }
} }
s.server.db.Exec(fmt.Sprintf(`UPDATE warehouse SET equip%d=$1 WHERE character_id=$2`, pkt.BoxIndex), mhfitem.SerializeWarehouseEquipment(fEquip), s.charID) database.Exec(fmt.Sprintf(`UPDATE warehouse SET equip%d=$1 WHERE character_id=$2`, pkt.BoxIndex), mhfitem.SerializeWarehouseEquipment(fEquip), s.CharID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -3,6 +3,8 @@ package channelserver
import ( import (
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"fmt"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -10,37 +12,49 @@ import (
func handleMsgMhfAddKouryouPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAddKouryouPoint(s *Session, p mhfpacket.MHFPacket) {
// hunting with both ranks maxed gets you these // hunting with both ranks maxed gets you these
pkt := p.(*mhfpacket.MsgMhfAddKouryouPoint) pkt := p.(*mhfpacket.MsgMhfAddKouryouPoint)
var points int database, err := db.GetDB()
err := s.server.db.QueryRow("UPDATE characters SET kouryou_point=COALESCE(kouryou_point + $1, $1) WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.charID).Scan(&points)
if err != nil { if err != nil {
s.logger.Error("Failed to update KouryouPoint in db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var points int
err = database.QueryRow("UPDATE characters SET kouryou_point=COALESCE(kouryou_point + $1, $1) WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.CharID).Scan(&points)
if err != nil {
s.Logger.Error("Failed to update KouryouPoint in db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(uint32(points)) resp.WriteUint32(uint32(points))
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfGetKouryouPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetKouryouPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetKouryouPoint) pkt := p.(*mhfpacket.MsgMhfGetKouryouPoint)
var points int database, err := db.GetDB()
err := s.server.db.QueryRow("SELECT COALESCE(kouryou_point, 0) FROM characters WHERE id = $1", s.charID).Scan(&points)
if err != nil { if err != nil {
s.logger.Error("Failed to get kouryou_point savedata from db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var points int
err = database.QueryRow("SELECT COALESCE(kouryou_point, 0) FROM characters WHERE id = $1", s.CharID).Scan(&points)
if err != nil {
s.Logger.Error("Failed to get kouryou_point savedata from db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(uint32(points)) resp.WriteUint32(uint32(points))
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfExchangeKouryouPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeKouryouPoint(s *Session, p mhfpacket.MHFPacket) {
// spent at the guildmaster, 10000 a roll // spent at the guildmaster, 10000 a roll
var points int var points int
pkt := p.(*mhfpacket.MsgMhfExchangeKouryouPoint) pkt := p.(*mhfpacket.MsgMhfExchangeKouryouPoint)
err := s.server.db.QueryRow("UPDATE characters SET kouryou_point=kouryou_point - $1 WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.charID).Scan(&points) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to update platemyset savedata in db", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("UPDATE characters SET kouryou_point=kouryou_point - $1 WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.CharID).Scan(&points)
if err != nil {
s.Logger.Error("Failed to update platemyset savedata in db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(uint32(points)) resp.WriteUint32(uint32(points))
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }

View File

@@ -2,7 +2,9 @@ package channelserver
import ( import (
"database/sql" "database/sql"
"erupe-ce/utils/db"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt"
"time" "time"
"erupe-ce/network/binpacket" "erupe-ce/network/binpacket"
@@ -31,21 +33,23 @@ type Mail struct {
} }
func (m *Mail) Send(s *Session, transaction *sql.Tx) error { func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
query := ` query := `
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite, is_sys_message) INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite, is_sys_message)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
` `
var err error
if transaction == nil { if transaction == nil {
_, err = s.server.db.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage) _, err = database.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
} else { } else {
_, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage) _, err = transaction.Exec(query, m.SenderID, m.RecipientID, m.Subject, m.Body, m.AttachedItemID, m.AttachedItemAmount, m.IsGuildInvite, m.IsSystemMessage)
} }
if err != nil { if err != nil {
s.logger.Error( s.Logger.Error(
"failed to send mail", "failed to send mail",
zap.Error(err), zap.Error(err),
zap.Uint32("senderID", m.SenderID), zap.Uint32("senderID", m.SenderID),
@@ -64,12 +68,16 @@ func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
} }
func (m *Mail) MarkRead(s *Session) error { func (m *Mail) MarkRead(s *Session) error {
_, err := s.server.db.Exec(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
_, err = database.Exec(`
UPDATE mail SET read = true WHERE id = $1 UPDATE mail SET read = true WHERE id = $1
`, m.ID) `, m.ID)
if err != nil { if err != nil {
s.logger.Error( s.Logger.Error(
"failed to mark mail as read", "failed to mark mail as read",
zap.Error(err), zap.Error(err),
zap.Int("mailID", m.ID), zap.Int("mailID", m.ID),
@@ -81,7 +89,11 @@ func (m *Mail) MarkRead(s *Session) error {
} }
func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) { func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
rows, err := s.server.db.Queryx(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`
SELECT SELECT
m.id, m.id,
m.sender_id, m.sender_id,
@@ -105,7 +117,7 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
`, charID) `, charID)
if err != nil { if err != nil {
s.logger.Error("failed to get mail for character", zap.Error(err), zap.Uint32("charID", charID)) s.Logger.Error("failed to get mail for character", zap.Error(err), zap.Uint32("charID", charID))
return nil, err return nil, err
} }
@@ -129,7 +141,11 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
} }
func GetMailByID(s *Session, ID int) (*Mail, error) { func GetMailByID(s *Session, ID int) (*Mail, error) {
row := s.server.db.QueryRowx(` database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
row := database.QueryRowx(`
SELECT SELECT
m.id, m.id,
m.sender_id, m.sender_id,
@@ -154,10 +170,10 @@ func GetMailByID(s *Session, ID int) (*Mail, error) {
mail := &Mail{} mail := &Mail{}
err := row.StructScan(mail) err = row.StructScan(mail)
if err != nil { if err != nil {
s.logger.Error( s.Logger.Error(
"failed to retrieve mail", "failed to retrieve mail",
zap.Error(err), zap.Error(err),
zap.Int("mailID", ID), zap.Int("mailID", ID),
@@ -190,11 +206,15 @@ func SendMailNotification(s *Session, m *Mail, recipient *Session) {
} }
func getCharacterName(s *Session, charID uint32) string { func getCharacterName(s *Session, charID uint32) string {
row := s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", charID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
row := database.QueryRow("SELECT name FROM characters WHERE id = $1", charID)
charName := "" charName := ""
err := row.Scan(&charName) err = row.Scan(&charName)
if err != nil { if err != nil {
return "" return ""
@@ -204,32 +224,35 @@ func getCharacterName(s *Session, charID uint32) string {
func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReadMail) pkt := p.(*mhfpacket.MsgMhfReadMail)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
mailId := s.mailList[pkt.AccIndex] mailId := s.mailList[pkt.AccIndex]
if mailId == 0 { if mailId == 0 {
doAckBufSucceed(s, pkt.AckHandle, []byte{0}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0})
return return
} }
mail, err := GetMailByID(s, mailId) mail, err := GetMailByID(s, mailId)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, []byte{0}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0})
return return
} }
s.server.db.Exec(`UPDATE mail SET read = true WHERE id = $1`, mail.ID) database.Exec(`UPDATE mail SET read = true WHERE id = $1`, mail.ID)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
body := stringsupport.UTF8ToSJIS(mail.Body) body := stringsupport.UTF8ToSJIS(mail.Body)
bf.WriteNullTerminatedBytes(body) bf.WriteNullTerminatedBytes(body)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfListMail) pkt := p.(*mhfpacket.MsgMhfListMail)
mail, err := GetMailListForCharacter(s, s.charID) mail, err := GetMailListForCharacter(s, s.CharID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, []byte{0}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0})
return return
} }
@@ -290,64 +313,71 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
} }
} }
doAckBufSucceed(s, pkt.AckHandle, msg.Data()) DoAckBufSucceed(s, pkt.AckHandle, msg.Data())
} }
func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOprtMail) pkt := p.(*mhfpacket.MsgMhfOprtMail)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
mail, err := GetMailByID(s, s.mailList[pkt.AccIndex]) mail, err := GetMailByID(s, s.mailList[pkt.AccIndex])
if err != nil { if err != nil {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
switch pkt.Operation { switch pkt.Operation {
case mhfpacket.OperateMailDelete: case mhfpacket.OperateMailDelete:
s.server.db.Exec(`UPDATE mail SET deleted = true WHERE id = $1`, mail.ID) database.Exec(`UPDATE mail SET deleted = true WHERE id = $1`, mail.ID)
case mhfpacket.OperateMailLock: case mhfpacket.OperateMailLock:
s.server.db.Exec(`UPDATE mail SET locked = TRUE WHERE id = $1`, mail.ID) database.Exec(`UPDATE mail SET locked = TRUE WHERE id = $1`, mail.ID)
case mhfpacket.OperateMailUnlock: case mhfpacket.OperateMailUnlock:
s.server.db.Exec(`UPDATE mail SET locked = FALSE WHERE id = $1`, mail.ID) database.Exec(`UPDATE mail SET locked = FALSE WHERE id = $1`, mail.ID)
case mhfpacket.OperateMailAcquireItem: case mhfpacket.OperateMailAcquireItem:
s.server.db.Exec(`UPDATE mail SET attached_item_received = TRUE WHERE id = $1`, mail.ID) database.Exec(`UPDATE mail SET attached_item_received = TRUE WHERE id = $1`, mail.ID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSendMail) pkt := p.(*mhfpacket.MsgMhfSendMail)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
query := ` query := `
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite) INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite)
VALUES ($1, $2, $3, $4, $5, $6, $7) VALUES ($1, $2, $3, $4, $5, $6, $7)
` `
if pkt.RecipientID == 0 { // Guild mail if pkt.RecipientID == 0 { // Guild mail
g, err := GetGuildInfoByCharacterId(s, s.charID) g, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to get guild info for mail") s.Logger.Error("Failed to get guild info for mail")
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
gm, err := GetGuildMembers(s, g.ID, false) gm, err := GetGuildMembers(s, g.ID, false)
if err != nil { if err != nil {
s.logger.Error("Failed to get guild members for mail") s.Logger.Error("Failed to get guild members for mail")
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
for i := 0; i < len(gm); i++ { for i := 0; i < len(gm); i++ {
_, err := s.server.db.Exec(query, s.charID, gm[i].CharID, pkt.Subject, pkt.Body, 0, 0, false) _, err := database.Exec(query, s.CharID, gm[i].CharID, pkt.Subject, pkt.Body, 0, 0, false)
if err != nil { if err != nil {
s.logger.Error("Failed to send mail") s.Logger.Error("Failed to send mail")
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
} else { } else {
_, err := s.server.db.Exec(query, s.charID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false) _, err := database.Exec(query, s.CharID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false)
if err != nil { if err != nil {
s.logger.Error("Failed to send mail") s.Logger.Error("Failed to send mail")
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -1,13 +1,16 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" 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"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt"
"io" "io"
"time" "time"
@@ -17,22 +20,30 @@ import (
func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadPartner) pkt := p.(*mhfpacket.MsgMhfLoadPartner)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT partner FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT partner FROM characters WHERE id = $1", s.CharID).Scan(&data)
if len(data) == 0 { if len(data) == 0 {
s.logger.Error("Failed to load partner", zap.Error(err)) s.Logger.Error("Failed to load partner", zap.Error(err))
data = make([]byte, 9) data = make([]byte, 9)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePartner) pkt := p.(*mhfpacket.MsgMhfSavePartner)
dumpSaveData(s, pkt.RawDataPayload, "partner") database, err := db.GetDB()
_, err := s.server.db.Exec("UPDATE characters SET partner=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Error("Failed to save partner", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) dumpSaveData(s, pkt.RawDataPayload, "partner")
_, err = database.Exec("UPDATE characters SET partner=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil {
s.Logger.Error("Failed to save partner", zap.Error(err))
}
DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {
@@ -51,36 +62,44 @@ func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(dispatch.Unk) bf.WriteUint32(dispatch.Unk)
bf.WriteUint32(dispatch.Timestamp) bf.WriteUint32(dispatch.Timestamp)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi) pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi)
naviLength := 552 naviLength := 552
if s.server.erupeConfig.ClientID <= _config.G7 { if config.GetConfig().ClientID <= config.G7 {
naviLength = 280 naviLength = 280
} }
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.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, naviLength) data = make([]byte, naviLength)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi) pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.IsDataDiff { if pkt.IsDataDiff {
naviLength := 552 naviLength := 552
if s.server.erupeConfig.ClientID <= _config.G7 { if config.GetConfig().ClientID <= config.G7 {
naviLength = 280 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 := database.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil { if err != nil {
s.logger.Error("Failed to load hunternavi", zap.Error(err)) s.Logger.Error("Failed to load hunternavi", zap.Error(err))
} }
// 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.
@@ -90,22 +109,22 @@ func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {
} }
// Perform diff and compress it to write back to db // Perform diff and compress it to write back to db
s.logger.Info("Diffing...") s.Logger.Info("Diffing...")
saveOutput := deltacomp.ApplyDataDiff(pkt.RawDataPayload, data) saveOutput := deltacomp.ApplyDataDiff(pkt.RawDataPayload, data)
_, err = s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", saveOutput, s.charID) _, err = database.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", saveOutput, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save hunternavi", zap.Error(err)) s.Logger.Error("Failed to save hunternavi", zap.Error(err))
} }
s.logger.Info("Wrote recompressed hunternavi back to DB") s.Logger.Info("Wrote recompressed hunternavi back to DB")
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "hunternavi") dumpSaveData(s, pkt.RawDataPayload, "hunternavi")
// simply update database, no extra processing // simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := database.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save hunternavi", zap.Error(err)) s.Logger.Error("Failed to save hunternavi", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) {
@@ -116,9 +135,9 @@ func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) {
// struct Hunt // struct Hunt
// uint32 HuntID // uint32 HuntID
// uint32 MonID // uint32 MonID
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 0))
} }
} }
@@ -132,39 +151,51 @@ func handleMsgMhfEnumerateMercenaryLog(s *Session, p mhfpacket.MHFPacket) {
// []byte Name (len 18) // []byte Name (len 18)
// uint8 Unk // uint8 Unk
// uint8 Unk // uint8 Unk
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCreateMercenary) pkt := p.(*mhfpacket.MsgMhfCreateMercenary)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var nextID uint32 var nextID uint32
_ = s.server.db.QueryRow("SELECT nextval('rasta_id_seq')").Scan(&nextID) _ = database.QueryRow("SELECT nextval('rasta_id_seq')").Scan(&nextID)
s.server.db.Exec("UPDATE characters SET rasta_id=$1 WHERE id=$2", nextID, s.charID) database.Exec("UPDATE characters SET rasta_id=$1 WHERE id=$2", nextID, s.CharID)
bf.WriteUint32(nextID) bf.WriteUint32(nextID)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveMercenary) pkt := p.(*mhfpacket.MsgMhfSaveMercenary)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
dumpSaveData(s, pkt.MercData, "mercenary") dumpSaveData(s, pkt.MercData, "mercenary")
if len(pkt.MercData) > 0 { if len(pkt.MercData) > 0 {
temp := byteframe.NewByteFrameFromBytes(pkt.MercData) temp := byteframe.NewByteFrameFromBytes(pkt.MercData)
s.server.db.Exec("UPDATE characters SET savemercenary=$1, rasta_id=$2 WHERE id=$3", pkt.MercData, temp.ReadUint32(), s.charID) database.Exec("UPDATE characters SET savemercenary=$1, rasta_id=$2 WHERE id=$3", pkt.MercData, temp.ReadUint32(), s.CharID)
} }
s.server.db.Exec("UPDATE characters SET gcp=$1, pact_id=$2 WHERE id=$3", pkt.GCP, pkt.PactMercID, s.charID) database.Exec("UPDATE characters SET gcp=$1, pact_id=$2 WHERE id=$3", pkt.GCP, pkt.PactMercID, s.CharID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReadMercenaryW) pkt := p.(*mhfpacket.MsgMhfReadMercenaryW)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var pactID, cid uint32 var pactID, cid uint32
var name string var name string
s.server.db.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.charID).Scan(&pactID) database.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.CharID).Scan(&pactID)
if pactID > 0 { if pactID > 0 {
s.server.db.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid) database.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid)
bf.WriteUint8(1) // numLends bf.WriteUint8(1) // numLends
bf.WriteUint32(pactID) bf.WriteUint32(pactID)
bf.WriteUint32(cid) bf.WriteUint32(cid)
@@ -179,7 +210,7 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
var loans uint8 var loans uint8
temp := byteframe.NewByteFrame() temp := byteframe.NewByteFrame()
if pkt.Op < 2 { if pkt.Op < 2 {
rows, _ := s.server.db.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.charID) rows, _ := database.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.CharID)
for rows.Next() { for rows.Next() {
err := rows.Scan(&name, &cid, &pactID) err := rows.Scan(&name, &cid, &pactID)
if err != nil { if err != nil {
@@ -199,8 +230,8 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
if pkt.Op < 1 { if pkt.Op < 1 {
var data []byte var data []byte
var gcp uint32 var gcp uint32
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.charID).Scan(&data) database.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.CharID).Scan(&data)
s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.charID).Scan(&gcp) database.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.CharID).Scan(&gcp)
if len(data) == 0 { if len(data) == 0 {
bf.WriteBool(false) bf.WriteBool(false)
@@ -211,53 +242,69 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(gcp) bf.WriteUint32(gcp)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReadMercenaryM) pkt := p.(*mhfpacket.MsgMhfReadMercenaryM)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var data []byte var data []byte
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id = $1", pkt.CharID).Scan(&data) database.QueryRow("SELECT savemercenary FROM characters WHERE id = $1", pkt.CharID).Scan(&data)
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
if len(data) == 0 { if len(data) == 0 {
resp.WriteBool(false) resp.WriteBool(false)
} else { } else {
resp.WriteBytes(data) resp.WriteBytes(data)
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfContractMercenary) pkt := p.(*mhfpacket.MsgMhfContractMercenary)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch pkt.Op { switch pkt.Op {
case 0: // Form loan case 0: // Form loan
s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, pkt.CID) database.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) database.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.CharID)
case 2: // Cancel loan case 2: // Cancel loan
s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", pkt.CID) database.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", pkt.CID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadOtomoAirou) pkt := p.(*mhfpacket.MsgMhfLoadOtomoAirou)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT otomoairou FROM characters WHERE id = $1", s.charID).Scan(&data) err = database.QueryRow("SELECT otomoairou FROM characters WHERE id = $1", s.CharID).Scan(&data)
if len(data) == 0 { if len(data) == 0 {
s.logger.Error("Failed to load otomoairou", zap.Error(err)) s.Logger.Error("Failed to load otomoairou", zap.Error(err))
data = make([]byte, 10) data = make([]byte, 10)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveOtomoAirou) pkt := p.(*mhfpacket.MsgMhfSaveOtomoAirou)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
dumpSaveData(s, pkt.RawDataPayload, "otomoairou") dumpSaveData(s, pkt.RawDataPayload, "otomoairou")
decomp, err := nullcomp.Decompress(pkt.RawDataPayload[1:]) decomp, err := nullcomp.Decompress(pkt.RawDataPayload[1:])
if err != nil { if err != nil {
s.logger.Error("Failed to decompress airou", zap.Error(err)) s.Logger.Error("Failed to decompress airou", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
bf := byteframe.NewByteFrameFromBytes(decomp) bf := byteframe.NewByteFrameFromBytes(decomp)
@@ -270,7 +317,7 @@ func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
dataLen := bf.ReadUint32() dataLen := bf.ReadUint32()
catID := bf.ReadUint32() catID := bf.ReadUint32()
if catID == 0 { if catID == 0 {
_ = s.server.db.QueryRow("SELECT nextval('airou_id_seq')").Scan(&catID) _ = database.QueryRow("SELECT nextval('airou_id_seq')").Scan(&catID)
} }
exists := bf.ReadBool() exists := bf.ReadBool()
data := bf.ReadBytes(uint(dataLen) - 5) data := bf.ReadBytes(uint(dataLen) - 5)
@@ -287,12 +334,12 @@ func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
save.WriteUint8(catsExist) save.WriteUint8(catsExist)
comp, err := nullcomp.Compress(save.Data()) comp, err := nullcomp.Compress(save.Data())
if err != nil { if err != nil {
s.logger.Error("Failed to compress airou", zap.Error(err)) s.Logger.Error("Failed to compress airou", zap.Error(err))
} else { } else {
comp = append([]byte{0x01}, comp...) comp = append([]byte{0x01}, comp...)
s.server.db.Exec("UPDATE characters SET otomoairou=$1 WHERE id=$2", comp, s.charID) database.Exec("UPDATE characters SET otomoairou=$1 WHERE id=$2", comp, s.CharID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) {
@@ -311,7 +358,7 @@ func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint16(cat.WeaponID) resp.WriteUint16(cat.WeaponID)
resp.WriteUint32(0) // 32 bit unix timestamp, either time at which the cat stops being fatigued or the time at which it started resp.WriteUint32(0) // 32 bit unix timestamp, either time at which the cat stops being fatigued or the time at which it started
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
type Airou struct { type Airou struct {
@@ -326,17 +373,21 @@ type Airou struct {
} }
func getGuildAirouList(s *Session) []Airou { func getGuildAirouList(s *Session) []Airou {
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var guildCats []Airou var guildCats []Airou
bannedCats := make(map[uint32]int) bannedCats := make(map[uint32]int)
guild, err := GetGuildInfoByCharacterId(s, s.charID) guild, err := GetGuildInfoByCharacterId(s, s.CharID)
if err != nil { if err != nil {
return guildCats return guildCats
} }
rows, err := s.server.db.Query(`SELECT cats_used FROM guild_hunts gh rows, err := database.Query(`SELECT cats_used FROM guild_hunts gh
INNER JOIN characters c ON gh.host_id = c.id WHERE c.id=$1 INNER JOIN characters c ON gh.host_id = c.id WHERE c.id=$1
`, s.charID) `, s.CharID)
if err != nil { if err != nil {
s.logger.Warn("Failed to get recently used airous", zap.Error(err)) s.Logger.Warn("Failed to get recently used airous", zap.Error(err))
return guildCats return guildCats
} }
@@ -347,19 +398,19 @@ func getGuildAirouList(s *Session) []Airou {
if err != nil { if err != nil {
continue continue
} }
if startTemp.Add(time.Second * time.Duration(s.server.erupeConfig.GameplayOptions.TreasureHuntPartnyaCooldown)).Before(gametime.TimeAdjusted()) { if startTemp.Add(time.Second * time.Duration(config.GetConfig().GameplayOptions.TreasureHuntPartnyaCooldown)).Before(gametime.TimeAdjusted()) {
for i, j := range stringsupport.CSVElems(csvTemp) { for i, j := range stringsupport.CSVElems(csvTemp) {
bannedCats[uint32(j)] = i bannedCats[uint32(j)] = i
} }
} }
} }
rows, err = s.server.db.Query(`SELECT c.otomoairou FROM characters c rows, err = database.Query(`SELECT c.otomoairou FROM characters c
INNER JOIN guild_characters gc ON gc.character_id = c.id INNER JOIN guild_characters gc ON gc.character_id = c.id
WHERE gc.guild_id = $1 AND c.otomoairou IS NOT NULL WHERE gc.guild_id = $1 AND c.otomoairou IS NOT NULL
ORDER BY c.id LIMIT 60`, guild.ID) ORDER BY c.id LIMIT 60`, guild.ID)
if err != nil { if err != nil {
s.logger.Warn("Selecting otomoairou based on guild failed", zap.Error(err)) s.Logger.Warn("Selecting otomoairou based on guild failed", zap.Error(err))
return guildCats return guildCats
} }
@@ -373,7 +424,7 @@ func getGuildAirouList(s *Session) []Airou {
if data[0] == 1 { if data[0] == 1 {
decomp, err := nullcomp.Decompress(data[1:]) decomp, err := nullcomp.Decompress(data[1:])
if err != nil { if err != nil {
s.logger.Warn("decomp failure", zap.Error(err)) s.Logger.Warn("decomp failure", zap.Error(err))
continue continue
} }
bf := byteframe.NewByteFrameFromBytes(decomp) bf := byteframe.NewByteFrameFromBytes(decomp)

View File

@@ -3,6 +3,7 @@ package channelserver
import ( import (
"fmt" "fmt"
"erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
) )
@@ -13,18 +14,18 @@ func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) {
s.stage.Lock() s.stage.Lock()
newObj := &Object{ newObj := &Object{
id: s.NextObjectID(), id: s.NextObjectID(),
ownerCharID: s.charID, ownerCharID: s.CharID,
x: pkt.X, x: pkt.X,
y: pkt.Y, y: pkt.Y,
z: pkt.Z, z: pkt.Z,
} }
s.stage.objects[s.charID] = newObj s.stage.objects[s.CharID] = newObj
s.stage.Unlock() s.stage.Unlock()
// Response to our requesting client. // Response to our requesting client.
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(newObj.id) // New local obj handle. resp.WriteUint32(newObj.id) // New local obj handle.
doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, resp.Data())
// Duplicate the object creation to all sessions in the same stage. // Duplicate the object creation to all sessions in the same stage.
dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{ dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{
ObjID: newObj.id, ObjID: newObj.id,
@@ -34,7 +35,7 @@ func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) {
OwnerCharID: newObj.ownerCharID, OwnerCharID: newObj.ownerCharID,
} }
s.logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, newObj.id)) s.Logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, newObj.id))
s.stage.BroadcastMHF(dupObjUpdate, s) s.stage.BroadcastMHF(dupObjUpdate, s)
} }
@@ -42,11 +43,11 @@ func handleMsgSysDeleteObject(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysPositionObject(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysPositionObject(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysPositionObject) pkt := p.(*mhfpacket.MsgSysPositionObject)
if s.server.erupeConfig.DebugOptions.LogInboundMessages { if config.GetConfig().DebugOptions.LogInboundMessages {
fmt.Printf("[%s] with objectID [%d] move to (%f,%f,%f)\n\n", s.Name, pkt.ObjID, pkt.X, pkt.Y, pkt.Z) fmt.Printf("[%s] with objectID [%d] move to (%f,%f,%f)\n\n", s.Name, pkt.ObjID, pkt.X, pkt.Y, pkt.Z)
} }
s.stage.Lock() s.stage.Lock()
object, ok := s.stage.objects[s.charID] object, ok := s.stage.objects[s.CharID]
if ok { if ok {
object.x = pkt.X object.x = pkt.X
object.y = pkt.Y object.y = pkt.Y
@@ -64,16 +65,16 @@ func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) {
_ = p.(*mhfpacket.MsgSysSetObjectBinary) _ = p.(*mhfpacket.MsgSysSetObjectBinary)
/* This causes issues with PS3 as this actually sends with endiness! /* 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()
s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: 3}] = pkt.RawDataPayload s.Server.userBinaryParts[userBinaryPartID{charID: s.CharID, index: 3}] = pkt.RawDataPayload
s.server.userBinaryPartsLock.Unlock() s.Server.userBinaryPartsLock.Unlock()
msg := &mhfpacket.MsgSysNotifyUserBinary{ msg := &mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID, CharID: s.CharID,
BinaryType: 3, BinaryType: 3,
} }
s.server.BroadcastMHF(msg, s) s.Server.BroadcastMHF(msg, s)
} }
} }
*/ */

View File

@@ -4,40 +4,50 @@ import (
"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"
"erupe-ce/utils/db"
"fmt"
"go.uber.org/zap" "go.uber.org/zap"
) )
func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadPlateData) pkt := p.(*mhfpacket.MsgMhfLoadPlateData)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to load platedata", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckBufSucceed(s, pkt.AckHandle, data) err = database.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil {
s.Logger.Error("Failed to load platedata", zap.Error(err))
}
DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateData) pkt := p.(*mhfpacket.MsgMhfSavePlateData)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.IsDataDiff { if pkt.IsDataDiff {
var data []byte var data []byte
// Load existing save // Load existing save
err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data) err := database.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil { if err != nil {
s.logger.Error("Failed to load platedata", zap.Error(err)) s.Logger.Error("Failed to load platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
if len(data) > 0 { if len(data) > 0 {
// Decompress // Decompress
s.logger.Info("Decompressing...") s.Logger.Info("Decompressing...")
data, err = nullcomp.Decompress(data) data, err = nullcomp.Decompress(data)
if err != nil { if err != nil {
s.logger.Error("Failed to decompress platedata", zap.Error(err)) s.Logger.Error("Failed to decompress platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
} else { } else {
@@ -46,66 +56,73 @@ func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {
} }
// Perform diff and compress it to write back to db // Perform diff and compress it to write back to db
s.logger.Info("Diffing...") s.Logger.Info("Diffing...")
saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data)) saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data))
if err != nil { if err != nil {
s.logger.Error("Failed to diff and compress platedata", zap.Error(err)) s.Logger.Error("Failed to diff and compress platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
_, err = s.server.db.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", saveOutput, s.charID) _, err = database.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", saveOutput, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save platedata", zap.Error(err)) s.Logger.Error("Failed to save platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
s.logger.Info("Wrote recompressed platedata back to DB") s.Logger.Info("Wrote recompressed platedata back to DB")
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "platedata") dumpSaveData(s, pkt.RawDataPayload, "platedata")
// simply update database, no extra processing // simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := database.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save platedata", zap.Error(err)) s.Logger.Error("Failed to save platedata", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadPlateBox) pkt := p.(*mhfpacket.MsgMhfLoadPlateBox)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to load platebox", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
} }
doAckBufSucceed(s, pkt.AckHandle, data) err = database.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil {
s.Logger.Error("Failed to load platebox", zap.Error(err))
}
DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateBox) pkt := p.(*mhfpacket.MsgMhfSavePlateBox)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.IsDataDiff { if pkt.IsDataDiff {
var data []byte var data []byte
// Load existing save // Load existing save
err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data) err := database.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil { if err != nil {
s.logger.Error("Failed to load platebox", zap.Error(err)) s.Logger.Error("Failed to load platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
// Decompress // Decompress
if len(data) > 0 { if len(data) > 0 {
// Decompress // Decompress
s.logger.Info("Decompressing...") s.Logger.Info("Decompressing...")
data, err = nullcomp.Decompress(data) data, err = nullcomp.Decompress(data)
if err != nil { if err != nil {
s.logger.Error("Failed to decompress platebox", zap.Error(err)) s.Logger.Error("Failed to decompress platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
} else { } else {
@@ -114,51 +131,59 @@ func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {
} }
// Perform diff and compress it to write back to db // Perform diff and compress it to write back to db
s.logger.Info("Diffing...") s.Logger.Info("Diffing...")
saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data)) saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data))
if err != nil { if err != nil {
s.logger.Error("Failed to diff and compress platebox", zap.Error(err)) s.Logger.Error("Failed to diff and compress platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
_, err = s.server.db.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", saveOutput, s.charID) _, err = database.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", saveOutput, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save platebox", zap.Error(err)) s.Logger.Error("Failed to save platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return return
} }
s.logger.Info("Wrote recompressed platebox back to DB") s.Logger.Info("Wrote recompressed platebox back to DB")
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "platebox") dumpSaveData(s, pkt.RawDataPayload, "platebox")
// simply update database, no extra processing // simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := database.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save platebox", zap.Error(err)) s.Logger.Error("Failed to save platebox", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadPlateMyset) pkt := p.(*mhfpacket.MsgMhfLoadPlateMyset)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT platemyset FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT platemyset FROM characters WHERE id = $1", s.CharID).Scan(&data)
if len(data) == 0 { if len(data) == 0 {
s.logger.Error("Failed to load platemyset", zap.Error(err)) s.Logger.Error("Failed to load platemyset", zap.Error(err))
data = make([]byte, 1920) data = make([]byte, 1920)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateMyset) pkt := p.(*mhfpacket.MsgMhfSavePlateMyset)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
// looks to always return the full thing, simply update database, no extra processing // looks to always return the full thing, simply update database, no extra processing
dumpSaveData(s, pkt.RawDataPayload, "platemyset") dumpSaveData(s, pkt.RawDataPayload, "platemyset")
_, err := s.server.db.Exec("UPDATE characters SET platemyset=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err = database.Exec("UPDATE characters SET platemyset=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil { if err != nil {
s.logger.Error("Failed to save platemyset", zap.Error(err)) s.Logger.Error("Failed to save platemyset", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }

View File

@@ -4,10 +4,11 @@ import (
"database/sql" "database/sql"
"encoding/binary" "encoding/binary"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/decryption" "erupe-ce/utils/decryption"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"fmt" "fmt"
@@ -62,16 +63,16 @@ func BackportQuest(data []byte) []byte {
} }
fillLength := uint32(108) fillLength := uint32(108)
if _config.ErupeConfig.ClientID <= _config.S6 { if config.GetConfig().ClientID <= config.S6 {
fillLength = 44 fillLength = 44
} else if _config.ErupeConfig.ClientID <= _config.F5 { } else if config.GetConfig().ClientID <= config.F5 {
fillLength = 52 fillLength = 52
} else if _config.ErupeConfig.ClientID <= _config.G101 { } else if config.GetConfig().ClientID <= config.G101 {
fillLength = 76 fillLength = 76
} }
copy(data[wp:wp+fillLength], data[rp:rp+fillLength]) copy(data[wp:wp+fillLength], data[rp:rp+fillLength])
if _config.ErupeConfig.ClientID <= _config.G91 { if config.GetConfig().ClientID <= config.G91 {
patterns := [][]byte{ patterns := [][]byte{
{0x0A, 0x00, 0x01, 0x33, 0xD7, 0x00}, // 10% Armor Sphere -> Stone {0x0A, 0x00, 0x01, 0x33, 0xD7, 0x00}, // 10% Armor Sphere -> Stone
{0x06, 0x00, 0x02, 0x33, 0xD8, 0x00}, // 6% Armor Sphere+ -> Iron Ore {0x06, 0x00, 0x02, 0x33, 0xD8, 0x00}, // 6% Armor Sphere+ -> Iron Ore
@@ -94,8 +95,8 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysGetFile) pkt := p.(*mhfpacket.MsgSysGetFile)
if pkt.IsScenario { if pkt.IsScenario {
if s.server.erupeConfig.DebugOptions.QuestTools { if config.GetConfig().DebugOptions.QuestTools {
s.logger.Debug( s.Logger.Debug(
"Scenario", "Scenario",
zap.Uint8("CategoryID", pkt.ScenarioIdentifer.CategoryID), zap.Uint8("CategoryID", pkt.ScenarioIdentifer.CategoryID),
zap.Uint32("MainID", pkt.ScenarioIdentifer.MainID), zap.Uint32("MainID", pkt.ScenarioIdentifer.MainID),
@@ -105,49 +106,49 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
} }
filename := fmt.Sprintf("%d_0_0_0_S%d_T%d_C%d", pkt.ScenarioIdentifer.CategoryID, pkt.ScenarioIdentifer.MainID, pkt.ScenarioIdentifer.Flags, pkt.ScenarioIdentifer.ChapterID) filename := fmt.Sprintf("%d_0_0_0_S%d_T%d_C%d", pkt.ScenarioIdentifer.CategoryID, pkt.ScenarioIdentifer.MainID, pkt.ScenarioIdentifer.Flags, pkt.ScenarioIdentifer.ChapterID)
// Read the scenario file. // Read the scenario file.
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename))) data, err := os.ReadFile(filepath.Join(config.GetConfig().BinPath, fmt.Sprintf("scenarios/%s.bin", filename)))
if err != nil { if err != nil {
s.logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", s.server.erupeConfig.BinPath, filename)) s.Logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", config.GetConfig().BinPath, filename))
// This will crash the game. // This will crash the game.
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
return return
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} else { } else {
if s.server.erupeConfig.DebugOptions.QuestTools { if config.GetConfig().DebugOptions.QuestTools {
s.logger.Debug( s.Logger.Debug(
"Quest", "Quest",
zap.String("Filename", pkt.Filename), zap.String("Filename", pkt.Filename),
) )
} }
if s.server.erupeConfig.GameplayOptions.SeasonOverride { if config.GetConfig().GameplayOptions.SeasonOverride {
pkt.Filename = seasonConversion(s, pkt.Filename) pkt.Filename = seasonConversion(s, pkt.Filename)
} }
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) data, err := os.ReadFile(filepath.Join(config.GetConfig().BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename)))
if err != nil { if err != nil {
s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) s.Logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", config.GetConfig().BinPath, pkt.Filename))
// This will crash the game. // This will crash the game.
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
return return
} }
if _config.ErupeConfig.ClientID <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport { if config.GetConfig().ClientID <= config.Z1 && config.GetConfig().DebugOptions.AutoQuestBackport {
data = BackportQuest(decryption.UnpackSimple(data)) data = BackportQuest(decryption.UnpackSimple(data))
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
} }
func seasonConversion(s *Session, questFile string) string { func seasonConversion(s *Session, questFile string) string {
filename := fmt.Sprintf("%s%d", questFile[:6], s.server.Season()) filename := fmt.Sprintf("%s%d", questFile[:6], s.Server.Season())
// Return the seasonal file // Return the seasonal file
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil { if _, err := os.Stat(filepath.Join(config.GetConfig().BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil {
return filename return filename
} else { } else {
// Attempt to return the requested quest file if the seasonal file doesn't exist // Attempt to return the requested quest file if the seasonal file doesn't exist
if _, err = os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil { if _, err = os.Stat(filepath.Join(config.GetConfig().BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil {
return questFile return questFile
} }
@@ -169,34 +170,42 @@ func seasonConversion(s *Session, questFile string) string {
func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest) pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT savefavoritequest FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT savefavoritequest FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err == nil && len(data) > 0 { if err == nil && len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
} }
} }
func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveFavoriteQuest) pkt := p.(*mhfpacket.MsgMhfSaveFavoriteQuest)
dumpSaveData(s, pkt.Data, "favquest") dumpSaveData(s, pkt.Data, "favquest")
s.server.db.Exec("UPDATE characters SET savefavoritequest=$1 WHERE id=$2", pkt.Data, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("UPDATE characters SET savefavoritequest=$1 WHERE id=$2", pkt.Data, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func loadQuestFile(s *Session, questId int) []byte { func loadQuestFile(s *Session, questId int) []byte {
data, exists := s.server.questCacheData[questId] data, exists := s.Server.questCacheData[questId]
if exists && s.server.questCacheTime[questId].Add(time.Duration(s.server.erupeConfig.QuestCacheExpiry)*time.Second).After(time.Now()) { if exists && s.Server.questCacheTime[questId].Add(time.Duration(config.GetConfig().QuestCacheExpiry)*time.Second).After(time.Now()) {
return data return data
} }
file, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%05dd0.bin", questId))) file, err := os.ReadFile(filepath.Join(config.GetConfig().BinPath, fmt.Sprintf("quests/%05dd0.bin", questId)))
if err != nil { if err != nil {
return nil return nil
} }
decrypted := decryption.UnpackSimple(file) decrypted := decryption.UnpackSimple(file)
if _config.ErupeConfig.ClientID <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport { if config.GetConfig().ClientID <= config.Z1 && config.GetConfig().DebugOptions.AutoQuestBackport {
decrypted = BackportQuest(decrypted) decrypted = BackportQuest(decrypted)
} }
fileBytes := byteframe.NewByteFrameFromBytes(decrypted) fileBytes := byteframe.NewByteFrameFromBytes(decrypted)
@@ -204,13 +213,13 @@ func loadQuestFile(s *Session, questId int) []byte {
fileBytes.Seek(int64(fileBytes.ReadUint32()), 0) fileBytes.Seek(int64(fileBytes.ReadUint32()), 0)
bodyLength := 320 bodyLength := 320
if _config.ErupeConfig.ClientID <= _config.S6 { if config.GetConfig().ClientID <= config.S6 {
bodyLength = 160 bodyLength = 160
} else if _config.ErupeConfig.ClientID <= _config.F5 { } else if config.GetConfig().ClientID <= config.F5 {
bodyLength = 168 bodyLength = 168
} else if _config.ErupeConfig.ClientID <= _config.G101 { } else if config.GetConfig().ClientID <= config.G101 {
bodyLength = 192 bodyLength = 192
} else if _config.ErupeConfig.ClientID <= _config.Z1 { } else if config.GetConfig().ClientID <= config.Z1 {
bodyLength = 224 bodyLength = 224
} }
@@ -240,8 +249,8 @@ func loadQuestFile(s *Session, questId int) []byte {
} }
questBody.WriteBytes(newStrings.Data()) questBody.WriteBytes(newStrings.Data())
s.server.questCacheData[questId] = questBody.Data() s.Server.questCacheData[questId] = questBody.Data()
s.server.questCacheTime[questId] = time.Now() s.Server.questCacheTime[questId] = time.Now()
return questBody.Data() return questBody.Data()
} }
@@ -263,15 +272,15 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
bf.WriteUint8(0) // Unk bf.WriteUint8(0) // Unk
switch questType { switch questType {
case 16: case 16:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.RegularRavienteMaxPlayers) bf.WriteUint8(config.GetConfig().GameplayOptions.RegularRavienteMaxPlayers)
case 22: case 22:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.ViolentRavienteMaxPlayers) bf.WriteUint8(config.GetConfig().GameplayOptions.ViolentRavienteMaxPlayers)
case 40: case 40:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.BerserkRavienteMaxPlayers) bf.WriteUint8(config.GetConfig().GameplayOptions.BerserkRavienteMaxPlayers)
case 50: case 50:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.ExtremeRavienteMaxPlayers) bf.WriteUint8(config.GetConfig().GameplayOptions.ExtremeRavienteMaxPlayers)
case 51: case 51:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.SmallBerserkRavienteMaxPlayers) bf.WriteUint8(config.GetConfig().GameplayOptions.SmallBerserkRavienteMaxPlayers)
default: default:
bf.WriteUint8(maxPlayers) bf.WriteUint8(maxPlayers)
} }
@@ -282,7 +291,7 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
bf.WriteBool(true) bf.WriteBool(true)
} }
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
if _config.ErupeConfig.ClientID >= _config.G2 { if config.GetConfig().ClientID >= config.G2 {
bf.WriteUint32(mark) bf.WriteUint32(mark)
} }
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
@@ -295,7 +304,7 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
bf.Seek(25, 0) bf.Seek(25, 0)
flagByte := bf.ReadUint8() flagByte := bf.ReadUint8()
bf.Seek(25, 0) bf.Seek(25, 0)
if s.server.erupeConfig.GameplayOptions.SeasonOverride { if config.GetConfig().GameplayOptions.SeasonOverride {
bf.WriteUint8(flagByte & 0b11100000) bf.WriteUint8(flagByte & 0b11100000)
} else { } else {
// Allow for seasons to be specified in database, otherwise use the one in the file. // Allow for seasons to be specified in database, otherwise use the one in the file.
@@ -326,11 +335,14 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
var totalCount, returnedCount uint16 var totalCount, returnedCount uint16
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(0) bf.WriteUint16(0)
database, err := db.GetDB()
rows, err := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, COALESCE(flags, -1), start_time, COALESCE(active_days, 0) AS active_days, COALESCE(inactive_days, 0) AS inactive_days FROM event_quests ORDER BY quest_id") if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, COALESCE(flags, -1), start_time, COALESCE(active_days, 0) AS active_days, COALESCE(inactive_days, 0) AS inactive_days FROM event_quests ORDER BY quest_id")
if err == nil { if err == nil {
currentTime := time.Now() currentTime := time.Now()
tx, _ := s.server.db.Begin() tx, _ := database.Begin()
for rows.Next() { for rows.Next() {
var id, mark uint32 var id, mark uint32
@@ -340,7 +352,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
err = rows.Scan(&id, &maxPlayers, &questType, &questId, &mark, &flags, &startTime, &activeDays, &inactiveDays) err = rows.Scan(&id, &maxPlayers, &questType, &questId, &mark, &flags, &startTime, &activeDays, &inactiveDays)
if err != nil { if err != nil {
s.logger.Error("Failed to scan event quest row", zap.Error(err)) s.Logger.Error("Failed to scan event quest row", zap.Error(err))
continue continue
} }
@@ -375,11 +387,11 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
data, err := makeEventQuest(s, rows) data, err := makeEventQuest(s, rows)
if err != nil { if err != nil {
s.logger.Error("Failed to make event quest", zap.Error(err)) s.Logger.Error("Failed to make event quest", zap.Error(err))
continue continue
} else { } else {
if len(data) > 896 || len(data) < 352 { if len(data) > 896 || len(data) < 352 {
s.logger.Error("Invalid quest data length", zap.Int("len", len(data))) s.Logger.Error("Invalid quest data length", zap.Int("len", len(data)))
continue continue
} else { } else {
totalCount++ totalCount++
@@ -504,54 +516,54 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
{ID: 1180, Value: 5}, {ID: 1180, Value: 5},
} }
tuneValues = append(tuneValues, tuneValue{1020, uint16(s.server.erupeConfig.GameplayOptions.GCPMultiplier * 100)}) tuneValues = append(tuneValues, tuneValue{1020, uint16(config.GetConfig().GameplayOptions.GCPMultiplier * 100)})
tuneValues = append(tuneValues, tuneValue{1029, uint16(s.server.erupeConfig.GameplayOptions.GUrgentRate * 100)}) tuneValues = append(tuneValues, tuneValue{1029, uint16(config.GetConfig().GameplayOptions.GUrgentRate * 100)})
if s.server.erupeConfig.GameplayOptions.DisableHunterNavi { if config.GetConfig().GameplayOptions.DisableHunterNavi {
tuneValues = append(tuneValues, tuneValue{1037, 1}) tuneValues = append(tuneValues, tuneValue{1037, 1})
} }
if s.server.erupeConfig.GameplayOptions.EnableKaijiEvent { if config.GetConfig().GameplayOptions.EnableKaijiEvent {
tuneValues = append(tuneValues, tuneValue{1106, 1}) tuneValues = append(tuneValues, tuneValue{1106, 1})
} }
if s.server.erupeConfig.GameplayOptions.EnableHiganjimaEvent { if config.GetConfig().GameplayOptions.EnableHiganjimaEvent {
tuneValues = append(tuneValues, tuneValue{1144, 1}) tuneValues = append(tuneValues, tuneValue{1144, 1})
} }
if s.server.erupeConfig.GameplayOptions.EnableNierEvent { if config.GetConfig().GameplayOptions.EnableNierEvent {
tuneValues = append(tuneValues, tuneValue{1153, 1}) tuneValues = append(tuneValues, tuneValue{1153, 1})
} }
if s.server.erupeConfig.GameplayOptions.DisableRoad { if config.GetConfig().GameplayOptions.DisableRoad {
tuneValues = append(tuneValues, tuneValue{1155, 1}) tuneValues = append(tuneValues, tuneValue{1155, 1})
} }
// get_hrp_rate_from_rank // get_hrp_rate_from_rank
tuneValues = append(tuneValues, getTuneValueRange(3000, uint16(s.server.erupeConfig.GameplayOptions.HRPMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3000, uint16(config.GetConfig().GameplayOptions.HRPMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3338, uint16(s.server.erupeConfig.GameplayOptions.HRPMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3338, uint16(config.GetConfig().GameplayOptions.HRPMultiplierNC*100))...)
// get_srp_rate_from_rank // get_srp_rate_from_rank
tuneValues = append(tuneValues, getTuneValueRange(3013, uint16(s.server.erupeConfig.GameplayOptions.SRPMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3013, uint16(config.GetConfig().GameplayOptions.SRPMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3351, uint16(s.server.erupeConfig.GameplayOptions.SRPMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3351, uint16(config.GetConfig().GameplayOptions.SRPMultiplierNC*100))...)
// get_grp_rate_from_rank // get_grp_rate_from_rank
tuneValues = append(tuneValues, getTuneValueRange(3026, uint16(s.server.erupeConfig.GameplayOptions.GRPMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3026, uint16(config.GetConfig().GameplayOptions.GRPMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3364, uint16(s.server.erupeConfig.GameplayOptions.GRPMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3364, uint16(config.GetConfig().GameplayOptions.GRPMultiplierNC*100))...)
// get_gsrp_rate_from_rank // get_gsrp_rate_from_rank
tuneValues = append(tuneValues, getTuneValueRange(3039, uint16(s.server.erupeConfig.GameplayOptions.GSRPMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3039, uint16(config.GetConfig().GameplayOptions.GSRPMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3377, uint16(s.server.erupeConfig.GameplayOptions.GSRPMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3377, uint16(config.GetConfig().GameplayOptions.GSRPMultiplierNC*100))...)
// get_zeny_rate_from_hrank // get_zeny_rate_from_hrank
tuneValues = append(tuneValues, getTuneValueRange(3052, uint16(s.server.erupeConfig.GameplayOptions.ZennyMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3052, uint16(config.GetConfig().GameplayOptions.ZennyMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3390, uint16(s.server.erupeConfig.GameplayOptions.ZennyMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3390, uint16(config.GetConfig().GameplayOptions.ZennyMultiplierNC*100))...)
// get_zeny_rate_from_grank // get_zeny_rate_from_grank
tuneValues = append(tuneValues, getTuneValueRange(3078, uint16(s.server.erupeConfig.GameplayOptions.GZennyMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3078, uint16(config.GetConfig().GameplayOptions.GZennyMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3416, uint16(s.server.erupeConfig.GameplayOptions.GZennyMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3416, uint16(config.GetConfig().GameplayOptions.GZennyMultiplierNC*100))...)
// get_reward_rate_from_hrank // get_reward_rate_from_hrank
tuneValues = append(tuneValues, getTuneValueRange(3104, uint16(s.server.erupeConfig.GameplayOptions.MaterialMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3104, uint16(config.GetConfig().GameplayOptions.MaterialMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3442, uint16(s.server.erupeConfig.GameplayOptions.MaterialMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3442, uint16(config.GetConfig().GameplayOptions.MaterialMultiplierNC*100))...)
// get_reward_rate_from_grank // get_reward_rate_from_grank
tuneValues = append(tuneValues, getTuneValueRange(3130, uint16(s.server.erupeConfig.GameplayOptions.GMaterialMultiplier*100))...) tuneValues = append(tuneValues, getTuneValueRange(3130, uint16(config.GetConfig().GameplayOptions.GMaterialMultiplier*100))...)
tuneValues = append(tuneValues, getTuneValueRange(3468, uint16(s.server.erupeConfig.GameplayOptions.GMaterialMultiplierNC*100))...) tuneValues = append(tuneValues, getTuneValueRange(3468, uint16(config.GetConfig().GameplayOptions.GMaterialMultiplierNC*100))...)
// get_lottery_rate_from_hrank // get_lottery_rate_from_hrank
tuneValues = append(tuneValues, getTuneValueRange(3156, 0)...) tuneValues = append(tuneValues, getTuneValueRange(3156, 0)...)
tuneValues = append(tuneValues, getTuneValueRange(3494, 0)...) tuneValues = append(tuneValues, getTuneValueRange(3494, 0)...)
@@ -559,11 +571,11 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
tuneValues = append(tuneValues, getTuneValueRange(3182, 0)...) tuneValues = append(tuneValues, getTuneValueRange(3182, 0)...)
tuneValues = append(tuneValues, getTuneValueRange(3520, 0)...) tuneValues = append(tuneValues, getTuneValueRange(3520, 0)...)
// get_hagi_rate_from_hrank // get_hagi_rate_from_hrank
tuneValues = append(tuneValues, getTuneValueRange(3208, s.server.erupeConfig.GameplayOptions.ExtraCarves)...) tuneValues = append(tuneValues, getTuneValueRange(3208, config.GetConfig().GameplayOptions.ExtraCarves)...)
tuneValues = append(tuneValues, getTuneValueRange(3546, s.server.erupeConfig.GameplayOptions.ExtraCarvesNC)...) tuneValues = append(tuneValues, getTuneValueRange(3546, config.GetConfig().GameplayOptions.ExtraCarvesNC)...)
// get_hagi_rate_from_grank // get_hagi_rate_from_grank
tuneValues = append(tuneValues, getTuneValueRange(3234, s.server.erupeConfig.GameplayOptions.GExtraCarves)...) tuneValues = append(tuneValues, getTuneValueRange(3234, config.GetConfig().GameplayOptions.GExtraCarves)...)
tuneValues = append(tuneValues, getTuneValueRange(3572, s.server.erupeConfig.GameplayOptions.GExtraCarvesNC)...) tuneValues = append(tuneValues, getTuneValueRange(3572, config.GetConfig().GameplayOptions.GExtraCarvesNC)...)
// get_nboost_transcend_rate_from_hrank // get_nboost_transcend_rate_from_hrank
tuneValues = append(tuneValues, getTuneValueRange(3286, 200)...) tuneValues = append(tuneValues, getTuneValueRange(3286, 200)...)
tuneValues = append(tuneValues, getTuneValueRange(3312, 300)...) tuneValues = append(tuneValues, getTuneValueRange(3312, 300)...)
@@ -580,23 +592,23 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
tuneValues = temp tuneValues = temp
tuneLimit := 770 tuneLimit := 770
if _config.ErupeConfig.ClientID <= _config.G1 { if config.GetConfig().ClientID <= config.G1 {
tuneLimit = 256 tuneLimit = 256
} else if _config.ErupeConfig.ClientID <= _config.G3 { } else if config.GetConfig().ClientID <= config.G3 {
tuneLimit = 283 tuneLimit = 283
} else if _config.ErupeConfig.ClientID <= _config.GG { } else if config.GetConfig().ClientID <= config.GG {
tuneLimit = 315 tuneLimit = 315
} else if _config.ErupeConfig.ClientID <= _config.G61 { } else if config.GetConfig().ClientID <= config.G61 {
tuneLimit = 332 tuneLimit = 332
} else if _config.ErupeConfig.ClientID <= _config.G7 { } else if config.GetConfig().ClientID <= config.G7 {
tuneLimit = 339 tuneLimit = 339
} else if _config.ErupeConfig.ClientID <= _config.G81 { } else if config.GetConfig().ClientID <= config.G81 {
tuneLimit = 396 tuneLimit = 396
} else if _config.ErupeConfig.ClientID <= _config.G91 { } else if config.GetConfig().ClientID <= config.G91 {
tuneLimit = 694 tuneLimit = 694
} else if _config.ErupeConfig.ClientID <= _config.G101 { } else if config.GetConfig().ClientID <= config.G101 {
tuneLimit = 704 tuneLimit = 704
} else if _config.ErupeConfig.ClientID <= _config.Z2 { } else if config.GetConfig().ClientID <= config.Z2 {
tuneLimit = 750 tuneLimit = 750
} }
if len(tuneValues) > tuneLimit { if len(tuneValues) > tuneLimit {
@@ -644,7 +656,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
bf.Seek(0, io.SeekStart) bf.Seek(0, io.SeekStart)
bf.WriteUint16(returnedCount) bf.WriteUint16(returnedCount)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func getTuneValueRange(start uint16, value uint16) []tuneValue { func getTuneValueRange(start uint16, value uint16) []tuneValue {
@@ -682,5 +694,5 @@ func handleMsgMhfGetUdBonusQuestInfo(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint8(q.Unk6) resp.WriteUint8(q.Unk6)
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }

View File

@@ -1,6 +1,7 @@
package channelserver package channelserver
import ( import (
"erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"strings" "strings"
@@ -10,14 +11,14 @@ func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfRegisterEvent) pkt := p.(*mhfpacket.MsgMhfRegisterEvent)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
// Some kind of check if there's already a session // Some kind of check if there's already a session
if pkt.Unk1 && s.server.getRaviSemaphore() == nil { if pkt.Unk1 && s.Server.getRaviSemaphore() == nil {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
bf.WriteUint8(uint8(pkt.WorldID)) bf.WriteUint8(uint8(pkt.WorldID))
bf.WriteUint8(uint8(pkt.LandID)) bf.WriteUint8(uint8(pkt.LandID))
bf.WriteUint16(s.server.raviente.id) bf.WriteUint16(s.Server.raviente.id)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) {
@@ -71,23 +72,23 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
bf = byteframe.NewByteFrame() bf = byteframe.NewByteFrame()
var _old, _new uint32 var _old, _new uint32
s.server.raviente.Lock() s.Server.raviente.Lock()
for _, update := range raviUpdates { for _, update := range raviUpdates {
switch update.Op { switch update.Op {
case 2: case 2:
_old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, true) _old, _new = s.Server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, true)
case 13, 14: case 13, 14:
_old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, false) _old, _new = s.Server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, false)
} }
bf.WriteUint8(1) bf.WriteUint8(1)
bf.WriteUint8(update.Dest) bf.WriteUint8(update.Dest)
bf.WriteUint32(_old) bf.WriteUint32(_old)
bf.WriteUint32(_new) bf.WriteUint32(_new)
} }
s.server.raviente.Unlock() s.Server.raviente.Unlock()
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente { if config.GetConfig().GameplayOptions.LowLatencyRaviente {
s.notifyRavi() s.notifyRavi()
} }
} }
@@ -100,31 +101,31 @@ func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) {
for i := uint8(0); i < pkt.Values; i++ { for i := uint8(0); i < pkt.Values; i++ {
switch pkt.RegisterID { switch pkt.RegisterID {
case 0x40000: case 0x40000:
bf.WriteUint32(s.server.raviente.state[i]) bf.WriteUint32(s.Server.raviente.state[i])
case 0x50000: case 0x50000:
bf.WriteUint32(s.server.raviente.support[i]) bf.WriteUint32(s.Server.raviente.support[i])
case 0x60000: case 0x60000:
bf.WriteUint32(s.server.raviente.register[i]) bf.WriteUint32(s.Server.raviente.register[i])
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func (s *Session) notifyRavi() { func (s *Session) notifyRavi() {
sema := s.server.getRaviSemaphore() sema := s.Server.getRaviSemaphore()
if sema == nil { if sema == nil {
return return
} }
var temp mhfpacket.MHFPacket var temp mhfpacket.MHFPacket
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysLoadRegister{RegisterID: uint32(0x40000 + i*0x10000)} temp = &mhfpacket.MsgSysLoadRegister{RegisterID: uint32(0x40000 + i*0x10000)}
if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente { if config.GetConfig().GameplayOptions.LowLatencyRaviente {
for session := range sema.clients { for session := range sema.clients {
session.QueueSendMHF(temp) session.QueueSendMHF(temp)
} }
} else { } else {
for session := range sema.clients { for session := range sema.clients {
if session.charID == s.charID { if session.CharID == s.CharID {
session.QueueSendMHF(temp) session.QueueSendMHF(temp)
} }
} }
@@ -132,7 +133,7 @@ func (s *Session) notifyRavi() {
} }
} }
func (server *Server) getRaviSemaphore() *Semaphore { func (server *ChannelServer) getRaviSemaphore() *Semaphore {
for _, semaphore := range server.semaphore { for _, semaphore := range server.semaphore {
if strings.HasPrefix(semaphore.name, "hs_l0") && strings.HasSuffix(semaphore.name, "3") { if strings.HasPrefix(semaphore.name, "hs_l0") && strings.HasSuffix(semaphore.name, "3") {
return semaphore return semaphore

View File

@@ -1,6 +1,8 @@
package channelserver package channelserver
import ( import (
"erupe-ce/config"
"erupe-ce/utils/db"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"fmt" "fmt"
"os" "os"
@@ -18,11 +20,15 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
// saved every floor on road, holds values such as floors progressed, points etc. // saved every floor on road, holds values such as floors progressed, points etc.
// can be safely handled by the client // can be safely handled by the client
pkt := p.(*mhfpacket.MsgMhfSaveRengokuData) pkt := p.(*mhfpacket.MsgMhfSaveRengokuData)
dumpSaveData(s, pkt.RawDataPayload, "rengoku") database, err := db.GetDB()
_, err := s.server.db.Exec("UPDATE characters SET rengokudata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Error("Failed to save rengokudata", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) }
dumpSaveData(s, pkt.RawDataPayload, "rengoku")
_, err = database.Exec("UPDATE characters SET rengokudata=$1 WHERE id=$2", pkt.RawDataPayload, s.CharID)
if err != nil {
s.Logger.Error("Failed to save rengokudata", zap.Error(err))
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
@@ -33,23 +39,27 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
maxStageSp := bf.ReadUint32() maxStageSp := bf.ReadUint32()
maxScoreSp := bf.ReadUint32() maxScoreSp := bf.ReadUint32()
var t int var t int
err = s.server.db.QueryRow("SELECT character_id FROM rengoku_score WHERE character_id=$1", s.charID).Scan(&t) err = database.QueryRow("SELECT character_id FROM rengoku_score WHERE character_id=$1", s.CharID).Scan(&t)
if err != nil { if err != nil {
s.server.db.Exec("INSERT INTO rengoku_score (character_id) VALUES ($1)", s.charID) database.Exec("INSERT INTO rengoku_score (character_id) VALUES ($1)", s.CharID)
} }
s.server.db.Exec("UPDATE rengoku_score SET max_stages_mp=$1, max_points_mp=$2, max_stages_sp=$3, max_points_sp=$4 WHERE character_id=$5", maxStageMp, maxScoreMp, maxStageSp, maxScoreSp, s.charID) database.Exec("UPDATE rengoku_score SET max_stages_mp=$1, max_points_mp=$2, max_stages_sp=$3, max_points_sp=$4 WHERE character_id=$5", maxStageMp, maxScoreMp, maxStageSp, maxScoreSp, s.CharID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadRengokuData) pkt := p.(*mhfpacket.MsgMhfLoadRengokuData)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT rengokudata FROM characters WHERE id = $1", s.charID).Scan(&data) database, err := db.GetDB()
if err != nil { if err != nil {
s.logger.Error("Failed to load rengokudata", zap.Error(err)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT rengokudata FROM characters WHERE id = $1", s.CharID).Scan(&data)
if err != nil {
s.Logger.Error("Failed to load rengokudata", zap.Error(err))
} }
if len(data) > 0 { if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} else { } else {
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(0) resp.WriteUint32(0)
@@ -87,18 +97,18 @@ func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint32(0) resp.WriteUint32(0)
resp.WriteUint32(0) resp.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
} }
func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRengokuBinary) pkt := p.(*mhfpacket.MsgMhfGetRengokuBinary)
// a (massively out of date) version resides in the game's /dat/ folder or up to date can be pulled from packets // a (massively out of date) version resides in the game's /dat/ folder or up to date can be pulled from packets
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "rengoku_data.bin")) data, err := os.ReadFile(filepath.Join(config.GetConfig().BinPath, "rengoku_data.bin"))
if err != nil { if err != nil {
panic(err) panic(err)
} }
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
const rengokuScoreQuery = `, c.name FROM rengoku_score rs const rengokuScoreQuery = `, c.name FROM rengoku_score rs
@@ -113,15 +123,15 @@ type RengokuScore struct {
func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateRengokuRanking) pkt := p.(*mhfpacket.MsgMhfEnumerateRengokuRanking)
guild, _ := GetGuildInfoByCharacterId(s, s.charID) guild, _ := GetGuildInfoByCharacterId(s, s.CharID)
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID) isApplicant, _ := guild.HasApplicationForCharID(s, s.CharID)
if isApplicant { if isApplicant {
guild = nil guild = nil
} }
if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 { if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 {
if guild == nil { if guild == nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 11))
return return
} }
} }
@@ -131,25 +141,28 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
i := uint32(1) i := uint32(1)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
scoreData := byteframe.NewByteFrame() scoreData := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var rows *sqlx.Rows var rows *sqlx.Rows
switch pkt.Leaderboard { switch pkt.Leaderboard {
case 0: case 0:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s ORDER BY max_stages_mp DESC", rengokuScoreQuery)) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s ORDER BY max_stages_mp DESC", rengokuScoreQuery))
case 1: case 1:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s ORDER BY max_points_mp DESC", rengokuScoreQuery)) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s ORDER BY max_points_mp DESC", rengokuScoreQuery))
case 2: case 2:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID)
case 3: case 3:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID)
case 4: case 4:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s ORDER BY max_stages_sp DESC", rengokuScoreQuery)) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s ORDER BY max_stages_sp DESC", rengokuScoreQuery))
case 5: case 5:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s ORDER BY max_points_sp DESC", rengokuScoreQuery)) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s ORDER BY max_points_sp DESC", rengokuScoreQuery))
case 6: case 6:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID)
case 7: case 7:
rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID) rows, _ = database.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID)
} }
for rows.Next() { for rows.Next() {
@@ -177,7 +190,7 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
} }
bf.WriteUint8(uint8(i) - 1) bf.WriteUint8(uint8(i) - 1)
bf.WriteBytes(scoreData.Data()) bf.WriteBytes(scoreData.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) {
@@ -186,5 +199,5 @@ func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(0) // Max stage overall MP rank bf.WriteUint32(0) // Max stage overall MP rank
bf.WriteUint32(0) // Max RdP overall MP rank bf.WriteUint32(0) // Max RdP overall MP rank
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -6,14 +6,14 @@ func handleMsgSysReserve188(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysReserve188) pkt := p.(*mhfpacket.MsgSysReserve188)
// Left as raw bytes because I couldn't easily find the request or resp parser function in the binary. // Left as raw bytes because I couldn't easily find the request or resp parser function in the binary.
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgSysReserve18B(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysReserve18B(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysReserve18B) pkt := p.(*mhfpacket.MsgSysReserve18B)
// Left as raw bytes because I couldn't easily find the request or resp parser function in the binary. // Left as raw bytes because I couldn't easily find the request or resp parser function in the binary.
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x3C}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x3C})
} }
func handleMsgSysReserve55(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysReserve55(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -12,21 +12,21 @@ func handleMsgMhfGetAdditionalBeatReward(s *Session, p mhfpacket.MHFPacket) {
// Actual response in packet captures are all just giant batches of null bytes // Actual response in packet captures are all just giant batches of null bytes
// I'm assuming this is because it used to be tied to an actual event and // I'm assuming this is because it used to be tied to an actual event and
// they never bothered killing off the packet when they made it static // they never bothered killing off the packet when they made it static
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x104)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x104))
} }
func handleMsgMhfGetUdRankingRewardList(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdRankingRewardList(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdRankingRewardList) pkt := p.(*mhfpacket.MsgMhfGetUdRankingRewardList)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000") data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfGetRewardSong(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetRewardSong(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRewardSong) pkt := p.(*mhfpacket.MsgMhfGetRewardSong)
// Temporary canned response // Temporary canned response
data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000") data, _ := hex.DecodeString("0100001600000A5397DF00000000000000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfUseRewardSong(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfUseRewardSong(s *Session, p mhfpacket.MHFPacket) {}
@@ -39,7 +39,7 @@ func handleMsgMhfAcquireMonthlyReward(s *Session, p mhfpacket.MHFPacket) {
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(0) resp.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -12,7 +12,7 @@ func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
type WeeklySeibatuRankingReward struct { type WeeklySeibatuRankingReward struct {
@@ -40,7 +40,7 @@ func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket
bf.WriteInt32(reward.Unk5) bf.WriteInt32(reward.Unk5)
data = append(data, bf) data = append(data, bf)
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket) {
@@ -49,7 +49,7 @@ func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket)
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteBytes(make([]byte, 32)) bf.WriteBytes(make([]byte, 32))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) {
@@ -65,7 +65,7 @@ func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint32(1) resp.WriteUint32(1)
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) {
@@ -75,13 +75,13 @@ func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfUpdateBeatLevel(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateBeatLevel(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateBeatLevel) pkt := p.(*mhfpacket.MsgMhfUpdateBeatLevel)
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) {
@@ -96,11 +96,11 @@ func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(0) bf.WriteUint32(0)
bf.WriteBytes(make([]byte, 32)) bf.WriteBytes(make([]byte, 32))
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfReadBeatLevelMyRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadBeatLevelMyRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReadBeatLevelMyRanking) pkt := p.(*mhfpacket.MsgMhfReadBeatLevelMyRanking)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -11,39 +11,39 @@ import (
) )
func removeSessionFromSemaphore(s *Session) { func removeSessionFromSemaphore(s *Session) {
s.server.semaphoreLock.Lock() s.Server.semaphoreLock.Lock()
for _, semaphore := range s.server.semaphore { for _, semaphore := range s.Server.semaphore {
if _, exists := semaphore.clients[s]; exists { if _, exists := semaphore.clients[s]; exists {
delete(semaphore.clients, s) delete(semaphore.clients, s)
} }
} }
s.server.semaphoreLock.Unlock() s.Server.semaphoreLock.Unlock()
} }
func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCreateSemaphore) pkt := p.(*mhfpacket.MsgSysCreateSemaphore)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d})
} }
func destructEmptySemaphores(s *Session) { func destructEmptySemaphores(s *Session) {
s.server.semaphoreLock.Lock() s.Server.semaphoreLock.Lock()
for id, sema := range s.server.semaphore { for id, sema := range s.Server.semaphore {
if len(sema.clients) == 0 { if len(sema.clients) == 0 {
delete(s.server.semaphore, id) delete(s.Server.semaphore, id)
if strings.HasPrefix(id, "hs_l0") { if strings.HasPrefix(id, "hs_l0") {
s.server.resetRaviente() s.Server.resetRaviente()
} }
s.logger.Debug("Destructed semaphore", zap.String("sema.name", id)) s.Logger.Debug("Destructed semaphore", zap.String("sema.name", id))
} }
} }
s.server.semaphoreLock.Unlock() s.Server.semaphoreLock.Unlock()
} }
func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysDeleteSemaphore) pkt := p.(*mhfpacket.MsgSysDeleteSemaphore)
destructEmptySemaphores(s) destructEmptySemaphores(s)
s.server.semaphoreLock.Lock() s.Server.semaphoreLock.Lock()
for id, sema := range s.server.semaphore { for id, sema := range s.Server.semaphore {
if sema.id == pkt.SemaphoreID { if sema.id == pkt.SemaphoreID {
for session := range sema.clients { for session := range sema.clients {
if s == session { if s == session {
@@ -51,22 +51,22 @@ func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) {
} }
} }
if len(sema.clients) == 0 { if len(sema.clients) == 0 {
delete(s.server.semaphore, id) delete(s.Server.semaphore, id)
if strings.HasPrefix(id, "hs_l0") { if strings.HasPrefix(id, "hs_l0") {
s.server.resetRaviente() s.Server.resetRaviente()
} }
s.logger.Debug("Destructed semaphore", zap.String("sema.name", id)) s.Logger.Debug("Destructed semaphore", zap.String("sema.name", id))
} }
} }
} }
s.server.semaphoreLock.Unlock() s.Server.semaphoreLock.Unlock()
} }
func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCreateAcquireSemaphore) pkt := p.(*mhfpacket.MsgSysCreateAcquireSemaphore)
SemaphoreID := pkt.SemaphoreID SemaphoreID := pkt.SemaphoreID
if s.server.HasSemaphore(s) { if s.Server.HasSemaphore(s) {
s.semaphoreMode = !s.semaphoreMode s.semaphoreMode = !s.semaphoreMode
} }
if s.semaphoreMode { if s.semaphoreMode {
@@ -75,22 +75,22 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
s.semaphoreID[0]++ s.semaphoreID[0]++
} }
newSemaphore, exists := s.server.semaphore[SemaphoreID] newSemaphore, exists := s.Server.semaphore[SemaphoreID]
if !exists { if !exists {
s.server.semaphoreLock.Lock() s.Server.semaphoreLock.Lock()
if strings.HasPrefix(SemaphoreID, "hs_l0") { if strings.HasPrefix(SemaphoreID, "hs_l0") {
suffix, _ := strconv.Atoi(pkt.SemaphoreID[len(pkt.SemaphoreID)-1:]) suffix, _ := strconv.Atoi(pkt.SemaphoreID[len(pkt.SemaphoreID)-1:])
s.server.semaphore[SemaphoreID] = &Semaphore{ s.Server.semaphore[SemaphoreID] = &Semaphore{
name: pkt.SemaphoreID, name: pkt.SemaphoreID,
id: uint32((suffix + 1) * 0x10000), id: uint32((suffix + 1) * 0x10000),
clients: make(map[*Session]uint32), clients: make(map[*Session]uint32),
maxPlayers: 127, maxPlayers: 127,
} }
} else { } else {
s.server.semaphore[SemaphoreID] = NewSemaphore(s, SemaphoreID, 1) s.Server.semaphore[SemaphoreID] = NewSemaphore(s, SemaphoreID, 1)
} }
newSemaphore = s.server.semaphore[SemaphoreID] newSemaphore = s.Server.semaphore[SemaphoreID]
s.server.semaphoreLock.Unlock() s.Server.semaphoreLock.Unlock()
} }
newSemaphore.Lock() newSemaphore.Lock()
@@ -99,7 +99,7 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
if _, exists := newSemaphore.clients[s]; exists { if _, exists := newSemaphore.clients[s]; exists {
bf.WriteUint32(newSemaphore.id) bf.WriteUint32(newSemaphore.id)
} else if uint16(len(newSemaphore.clients)) < newSemaphore.maxPlayers { } else if uint16(len(newSemaphore.clients)) < newSemaphore.maxPlayers {
newSemaphore.clients[s] = s.charID newSemaphore.clients[s] = s.CharID
s.Lock() s.Lock()
s.semaphore = newSemaphore s.semaphore = newSemaphore
s.Unlock() s.Unlock()
@@ -107,18 +107,18 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
} else { } else {
bf.WriteUint32(0) bf.WriteUint32(0)
} }
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysAcquireSemaphore) pkt := p.(*mhfpacket.MsgSysAcquireSemaphore)
if sema, exists := s.server.semaphore[pkt.SemaphoreID]; exists { if sema, exists := s.Server.semaphore[pkt.SemaphoreID]; exists {
sema.host = s sema.host = s
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(sema.id) bf.WriteUint32(sema.id)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} }
} }
@@ -129,10 +129,10 @@ func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCheckSemaphore) pkt := p.(*mhfpacket.MsgSysCheckSemaphore)
resp := []byte{0x00, 0x00, 0x00, 0x00} resp := []byte{0x00, 0x00, 0x00, 0x00}
s.server.semaphoreLock.Lock() s.Server.semaphoreLock.Lock()
if _, exists := s.server.semaphore[pkt.SemaphoreID]; exists { if _, exists := s.Server.semaphore[pkt.SemaphoreID]; exists {
resp = []byte{0x00, 0x00, 0x00, 0x01} resp = []byte{0x00, 0x00, 0x00, 0x01}
} }
s.server.semaphoreLock.Unlock() s.Server.semaphoreLock.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, resp) DoAckSimpleSucceed(s, pkt.AckHandle, resp)
} }

View File

@@ -1,11 +1,13 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"fmt"
"math/rand" "math/rand"
) )
@@ -62,7 +64,7 @@ func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) {
bf.WriteUint16(uint16(len(items))) bf.WriteUint16(uint16(len(items)))
bf.WriteUint16(uint16(len(items))) bf.WriteUint16(uint16(len(items)))
for _, item := range items { for _, item := range items {
if _config.ErupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
bf.WriteUint32(item.ID) bf.WriteUint32(item.ID)
} }
bf.WriteUint32(item.ItemID) bf.WriteUint32(item.ItemID)
@@ -70,19 +72,19 @@ func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) {
bf.WriteUint16(item.Quantity) bf.WriteUint16(item.Quantity)
bf.WriteUint16(item.MinHR) bf.WriteUint16(item.MinHR)
bf.WriteUint16(item.MinSR) bf.WriteUint16(item.MinSR)
if _config.ErupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
bf.WriteUint16(item.MinGR) bf.WriteUint16(item.MinGR)
} }
bf.WriteUint8(0) // Unk bf.WriteUint8(0) // Unk
bf.WriteUint8(item.StoreLevel) bf.WriteUint8(item.StoreLevel)
if _config.ErupeConfig.ClientID >= _config.Z2 { if config.GetConfig().ClientID >= config.Z2 {
bf.WriteUint16(item.MaxQuantity) bf.WriteUint16(item.MaxQuantity)
bf.WriteUint16(item.UsedQuantity) bf.WriteUint16(item.UsedQuantity)
} }
if _config.ErupeConfig.ClientID == _config.Z1 { if config.GetConfig().ClientID == config.Z1 {
bf.WriteUint8(uint8(item.RoadFloors)) bf.WriteUint8(uint8(item.RoadFloors))
bf.WriteUint8(uint8(item.RoadFatalis)) bf.WriteUint8(uint8(item.RoadFatalis))
} else if _config.ErupeConfig.ClientID >= _config.Z2 { } else if config.GetConfig().ClientID >= config.Z2 {
bf.WriteUint16(item.RoadFloors) bf.WriteUint16(item.RoadFloors)
bf.WriteUint16(item.RoadFatalis) bf.WriteUint16(item.RoadFatalis)
} }
@@ -92,10 +94,14 @@ func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) {
func getShopItems(s *Session, shopType uint8, shopID uint32) []ShopItem { func getShopItems(s *Session, shopType uint8, shopID uint32) []ShopItem {
var items []ShopItem var items []ShopItem
var temp ShopItem var temp ShopItem
rows, err := s.server.db.Queryx(`SELECT id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`SELECT id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity,
COALESCE((SELECT bought FROM shop_items_bought WHERE shop_item_id=si.id AND character_id=$3), 0) as used_quantity, COALESCE((SELECT bought FROM shop_items_bought WHERE shop_item_id=si.id AND character_id=$3), 0) as used_quantity,
road_floors, road_fatalis FROM shop_items si WHERE shop_type=$1 AND shop_id=$2 road_floors, road_fatalis FROM shop_items si WHERE shop_type=$1 AND shop_id=$2
`, shopType, shopID, s.charID) `, shopType, shopID, s.CharID)
if err == nil { if err == nil {
for rows.Next() { for rows.Next() {
err = rows.StructScan(&temp) err = rows.StructScan(&temp)
@@ -110,6 +116,10 @@ func getShopItems(s *Session, shopType uint8, shopID uint32) []ShopItem {
func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateShop) pkt := p.(*mhfpacket.MsgMhfEnumerateShop)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
// Generic Shop IDs // Generic Shop IDs
// 0: basic item // 0: basic item
// 1: gatherables // 1: gatherables
@@ -123,14 +133,14 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
switch pkt.ShopType { switch pkt.ShopType {
case 1: // Running gachas case 1: // Running gachas
// Fundamentally, gacha works completely differently, just hide it for now. // Fundamentally, gacha works completely differently, just hide it for now.
if _config.ErupeConfig.ClientID <= _config.G7 { if config.GetConfig().ClientID <= config.G7 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
rows, err := s.server.db.Queryx("SELECT id, min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden FROM gacha_shop") rows, err := database.Queryx("SELECT id, min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden FROM gacha_shop")
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
@@ -156,7 +166,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
ps.Uint8(bf, g.Name, true) ps.Uint8(bf, g.Name, true)
ps.Uint8(bf, g.URLBanner, false) ps.Uint8(bf, g.URLBanner, false)
ps.Uint8(bf, g.URLFeature, false) ps.Uint8(bf, g.URLFeature, false)
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
bf.WriteBool(g.Wide) bf.WriteBool(g.Wide)
ps.Uint8(bf, g.URLThumbnail, false) ps.Uint8(bf, g.URLThumbnail, false)
} }
@@ -166,23 +176,23 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0) bf.WriteUint16(0)
} }
bf.WriteUint8(g.GachaType) bf.WriteUint8(g.GachaType)
if _config.ErupeConfig.ClientID >= _config.G10 { if config.GetConfig().ClientID >= config.G10 {
bf.WriteBool(g.Hidden) bf.WriteBool(g.Hidden)
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
case 2: // Actual gacha case 2: // Actual gacha
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(pkt.ShopID) bf.WriteUint32(pkt.ShopID)
var gachaType int var gachaType int
s.server.db.QueryRow(`SELECT gacha_type FROM gacha_shop WHERE id = $1`, pkt.ShopID).Scan(&gachaType) database.QueryRow(`SELECT gacha_type FROM gacha_shop WHERE id = $1`, pkt.ShopID).Scan(&gachaType)
rows, err := s.server.db.Queryx(`SELECT entry_type, id, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points, COALESCE(name, '') AS name FROM gacha_entries WHERE gacha_id = $1 ORDER BY weight DESC`, pkt.ShopID) rows, err := database.Queryx(`SELECT entry_type, id, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points, COALESCE(name, '') AS name FROM gacha_entries WHERE gacha_id = $1 ORDER BY weight DESC`, pkt.ShopID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
var divisor float64 var divisor float64
s.server.db.QueryRow(`SELECT COALESCE(SUM(weight) / 100000.0, 0) AS chance FROM gacha_entries WHERE gacha_id = $1`, pkt.ShopID).Scan(&divisor) database.QueryRow(`SELECT COALESCE(SUM(weight) / 100000.0, 0) AS chance FROM gacha_entries WHERE gacha_id = $1`, pkt.ShopID).Scan(&divisor)
var entry GachaEntry var entry GachaEntry
var entries []GachaEntry var entries []GachaEntry
@@ -209,7 +219,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(ge.Rarity) bf.WriteUint8(ge.Rarity)
bf.WriteUint8(ge.Rolls) bf.WriteUint8(ge.Rolls)
rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, ge.ID) rows, err = database.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, ge.ID)
if err != nil { if err != nil {
bf.WriteUint8(0) bf.WriteUint8(0)
} else { } else {
@@ -235,7 +245,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(gi.Quantity) bf.WriteUint16(gi.Quantity)
} }
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
case 3: // Hunting Festival Exchange case 3: // Hunting Festival Exchange
fallthrough fallthrough
case 4: // N Points, 0-6 case 4: // N Points, 0-6
@@ -257,7 +267,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
items = items[:pkt.Limit] items = items[:pkt.Limit]
} }
writeShopItems(bf, items) writeShopItems(bf, items)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
} }
@@ -265,57 +275,73 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireExchangeShop) pkt := p.(*mhfpacket.MsgMhfAcquireExchangeShop)
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
exchanges := int(bf.ReadUint16()) exchanges := int(bf.ReadUint16())
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
for i := 0; i < exchanges; i++ { for i := 0; i < exchanges; i++ {
itemHash := bf.ReadUint32() itemHash := bf.ReadUint32()
if itemHash == 0 { if itemHash == 0 {
continue continue
} }
buyCount := bf.ReadUint32() buyCount := bf.ReadUint32()
s.server.db.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought) database.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought)
VALUES ($1,$2,$3) ON CONFLICT (character_id, shop_item_id) VALUES ($1,$2,$3) ON CONFLICT (character_id, shop_item_id)
DO UPDATE SET bought = bought + $3 DO UPDATE SET bought = bought + $3
WHERE EXCLUDED.character_id=$1 AND EXCLUDED.shop_item_id=$2 WHERE EXCLUDED.character_id=$1 AND EXCLUDED.shop_item_id=$2
`, s.charID, itemHash, buyCount) `, s.CharID, itemHash, buyCount)
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetGachaPlayHistory(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetGachaPlayHistory(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGachaPlayHistory) pkt := p.(*mhfpacket.MsgMhfGetGachaPlayHistory)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint8(1) bf.WriteUint8(1)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetGachaPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetGachaPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGachaPoint) pkt := p.(*mhfpacket.MsgMhfGetGachaPoint)
var fp, gp, gt uint32 var fp, gp, gt uint32
s.server.db.QueryRow("SELECT COALESCE(frontier_points, 0), COALESCE(gacha_premium, 0), COALESCE(gacha_trial, 0) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)", s.charID).Scan(&fp, &gp, &gt) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow("SELECT COALESCE(frontier_points, 0), COALESCE(gacha_premium, 0), COALESCE(gacha_trial, 0) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)", s.CharID).Scan(&fp, &gp, &gt)
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(gp) resp.WriteUint32(gp)
resp.WriteUint32(gt) resp.WriteUint32(gt)
resp.WriteUint32(fp) resp.WriteUint32(fp)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUseGachaPoint) pkt := p.(*mhfpacket.MsgMhfUseGachaPoint)
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if pkt.TrialCoins > 0 { if pkt.TrialCoins > 0 {
s.server.db.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.TrialCoins, s.charID) database.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.TrialCoins, s.CharID)
} }
if pkt.PremiumCoins > 0 { if pkt.PremiumCoins > 0 {
s.server.db.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.PremiumCoins, s.charID) database.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, pkt.PremiumCoins, s.CharID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func spendGachaCoin(s *Session, quantity uint16) { func spendGachaCoin(s *Session, quantity uint16) {
var gt uint16 var gt uint16
s.server.db.QueryRow(`SELECT COALESCE(gacha_trial, 0) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&gt) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow(`SELECT COALESCE(gacha_trial, 0) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&gt)
if quantity <= gt { if quantity <= gt {
s.server.db.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.charID) database.Exec(`UPDATE users u SET gacha_trial=gacha_trial-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.CharID)
} else { } else {
s.server.db.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.charID) database.Exec(`UPDATE users u SET gacha_premium=gacha_premium-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, quantity, s.CharID)
} }
} }
@@ -323,7 +349,11 @@ func transactGacha(s *Session, gachaID uint32, rollID uint8) (error, int) {
var itemType uint8 var itemType uint8
var itemNumber uint16 var itemNumber uint16
var rolls int var rolls int
err := s.server.db.QueryRowx(`SELECT item_type, item_number, rolls FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2`, gachaID, rollID).Scan(&itemType, &itemNumber, &rolls) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRowx(`SELECT item_type, item_number, rolls FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2`, gachaID, rollID).Scan(&itemType, &itemNumber, &rolls)
if err != nil { if err != nil {
return err, 0 return err, 0
} }
@@ -344,7 +374,7 @@ func transactGacha(s *Session, gachaID uint32, rollID uint8) (error, int) {
case 20: case 20:
spendGachaCoin(s, itemNumber) spendGachaCoin(s, itemNumber)
case 21: case 21:
s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", itemNumber, s.charID) database.Exec("UPDATE users u SET frontier_points=frontier_points-$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", itemNumber, s.CharID)
} }
return nil, rolls return nil, rolls
} }
@@ -352,7 +382,11 @@ func transactGacha(s *Session, gachaID uint32, rollID uint8) (error, int) {
func getGuaranteedItems(s *Session, gachaID uint32, rollID uint8) []GachaItem { func getGuaranteedItems(s *Session, gachaID uint32, rollID uint8) []GachaItem {
var rewards []GachaItem var rewards []GachaItem
var reward GachaItem var reward GachaItem
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = (SELECT id FROM gacha_entries WHERE entry_type = $1 AND gacha_id = $2)`, rollID, gachaID) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
items, err := database.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = (SELECT id FROM gacha_entries WHERE entry_type = $1 AND gacha_id = $2)`, rollID, gachaID)
if err == nil { if err == nil {
for items.Next() { for items.Next() {
items.StructScan(&reward) items.StructScan(&reward)
@@ -364,7 +398,11 @@ func getGuaranteedItems(s *Session, gachaID uint32, rollID uint8) []GachaItem {
func addGachaItem(s *Session, items []GachaItem) { func addGachaItem(s *Session, items []GachaItem) {
var data []byte var data []byte
s.server.db.QueryRow(`SELECT gacha_items FROM characters WHERE id = $1`, s.charID).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow(`SELECT gacha_items FROM characters WHERE id = $1`, s.CharID).Scan(&data)
if len(data) > 0 { if len(data) > 0 {
numItems := int(data[0]) numItems := int(data[0])
data = data[1:] data = data[1:]
@@ -384,7 +422,7 @@ func addGachaItem(s *Session, items []GachaItem) {
newItem.WriteUint16(items[i].ItemID) newItem.WriteUint16(items[i].ItemID)
newItem.WriteUint16(items[i].Quantity) newItem.WriteUint16(items[i].Quantity)
} }
s.server.db.Exec(`UPDATE characters SET gacha_items = $1 WHERE id = $2`, newItem.Data(), s.charID) database.Exec(`UPDATE characters SET gacha_items = $1 WHERE id = $2`, newItem.Data(), s.CharID)
} }
func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry, error) { func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry, error) {
@@ -419,7 +457,11 @@ func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry
func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReceiveGachaItem) pkt := p.(*mhfpacket.MsgMhfReceiveGachaItem)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(gacha_items, $2) FROM characters WHERE id = $1", s.charID, []byte{0x00}).Scan(&data) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT COALESCE(gacha_items, $2) FROM characters WHERE id = $1", s.CharID, []byte{0x00}).Scan(&data)
if err != nil { if err != nil {
data = []byte{0x00} data = []byte{0x00}
} }
@@ -429,9 +471,9 @@ func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint8(36) resp.WriteUint8(36)
resp.WriteBytes(data[1:181]) resp.WriteBytes(data[1:181])
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) DoAckBufSucceed(s, pkt.AckHandle, resp.Data())
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
if !pkt.Freeze { if !pkt.Freeze {
@@ -439,9 +481,9 @@ func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
update := byteframe.NewByteFrame() update := byteframe.NewByteFrame()
update.WriteUint8(uint8(len(data[181:]) / 5)) update.WriteUint8(uint8(len(data[181:]) / 5))
update.WriteBytes(data[181:]) update.WriteBytes(data[181:])
s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", update.Data(), s.charID) database.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", update.Data(), s.CharID)
} else { } else {
s.server.db.Exec("UPDATE characters SET gacha_items = null WHERE id = $1", s.charID) database.Exec("UPDATE characters SET gacha_items = null WHERE id = $1", s.CharID)
} }
} }
} }
@@ -453,15 +495,19 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
var entry GachaEntry var entry GachaEntry
var rewards []GachaItem var rewards []GachaItem
var reward GachaItem var reward GachaItem
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType) err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID) rows, err := database.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for rows.Next() { for rows.Next() {
@@ -475,7 +521,7 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
rewardEntries, err := getRandomEntries(entries, rolls, false) rewardEntries, err := getRandomEntries(entries, rolls, false)
temp := byteframe.NewByteFrame() temp := byteframe.NewByteFrame()
for i := range rewardEntries { for i := range rewardEntries {
rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID) rows, err = database.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil { if err != nil {
continue continue
} }
@@ -494,7 +540,7 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(uint8(len(rewards))) bf.WriteUint8(uint8(len(rewards)))
bf.WriteBytes(temp.Data()) bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
addGachaItem(s, rewards) addGachaItem(s, rewards)
} }
@@ -507,16 +553,20 @@ func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
var reward GachaItem var reward GachaItem
err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType) err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+(SELECT frontier_points FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.GachaID, pkt.RollType, s.charID) database, err := db.GetDB()
s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID)
s.server.db.Exec(`INSERT INTO gacha_stepup (gacha_id, step, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, pkt.RollType+1, s.charID)
rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("UPDATE users u SET frontier_points=frontier_points+(SELECT frontier_points FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.GachaID, pkt.RollType, s.CharID)
database.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.CharID)
database.Exec(`INSERT INTO gacha_stepup (gacha_id, step, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, pkt.RollType+1, s.CharID)
rows, err := database.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil {
DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for rows.Next() { for rows.Next() {
@@ -531,7 +581,7 @@ func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
rewardEntries, err := getRandomEntries(entries, rolls, false) rewardEntries, err := getRandomEntries(entries, rolls, false)
temp := byteframe.NewByteFrame() temp := byteframe.NewByteFrame()
for i := range rewardEntries { for i := range rewardEntries {
rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID) rows, err = database.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil { if err != nil {
continue continue
} }
@@ -557,7 +607,7 @@ func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(0) bf.WriteUint8(0)
} }
bf.WriteBytes(temp.Data()) bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
addGachaItem(s, rewards) addGachaItem(s, rewards)
addGachaItem(s, guaranteedItems) addGachaItem(s, guaranteedItems)
} }
@@ -566,24 +616,32 @@ func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetStepupStatus) pkt := p.(*mhfpacket.MsgMhfGetStepupStatus)
// TODO: Reset daily (noon) // TODO: Reset daily (noon)
var step uint8 var step uint8
s.server.db.QueryRow(`SELECT step FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID).Scan(&step) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow(`SELECT step FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.CharID).Scan(&step)
var stepCheck int var stepCheck int
s.server.db.QueryRow(`SELECT COUNT(1) FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2`, pkt.GachaID, step).Scan(&stepCheck) database.QueryRow(`SELECT COUNT(1) FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2`, pkt.GachaID, step).Scan(&stepCheck)
if stepCheck == 0 { if stepCheck == 0 {
s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID) database.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.CharID)
step = 0 step = 0
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint8(step) bf.WriteUint8(step)
bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix()))
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetBoxGachaInfo) pkt := p.(*mhfpacket.MsgMhfGetBoxGachaInfo)
entries, err := s.server.db.Queryx(`SELECT entry_id FROM gacha_box WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID) database, err := db.GetDB()
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
entries, err := database.Queryx(`SELECT entry_id FROM gacha_box WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.CharID)
if err != nil {
DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
var entryIDs []uint32 var entryIDs []uint32
@@ -598,7 +656,7 @@ func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(entryIDs[i]) bf.WriteUint32(entryIDs[i])
bf.WriteBool(true) bf.WriteBool(true)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
@@ -610,12 +668,16 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
var reward GachaItem var reward GachaItem
err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType) err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID) database, err := db.GetDB()
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil {
DoAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for rows.Next() { for rows.Next() {
@@ -626,11 +688,11 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
} }
rewardEntries, err := getRandomEntries(entries, rolls, true) rewardEntries, err := getRandomEntries(entries, rolls, true)
for i := range rewardEntries { for i := range rewardEntries {
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID) items, err := database.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil { if err != nil {
continue continue
} }
s.server.db.Exec(`INSERT INTO gacha_box (gacha_id, entry_id, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, rewardEntries[i].ID, s.charID) database.Exec(`INSERT INTO gacha_box (gacha_id, entry_id, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, rewardEntries[i].ID, s.CharID)
for items.Next() { for items.Next() {
err = items.StructScan(&reward) err = items.StructScan(&reward)
if err == nil { if err == nil {
@@ -645,38 +707,50 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(r.Quantity) bf.WriteUint16(r.Quantity)
bf.WriteUint8(0) bf.WriteUint8(0)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
addGachaItem(s, rewards) addGachaItem(s, rewards)
} }
func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfResetBoxGachaInfo) pkt := p.(*mhfpacket.MsgMhfResetBoxGachaInfo)
s.server.db.Exec("DELETE FROM gacha_box WHERE gacha_id = $1 AND character_id = $2", pkt.GachaID, s.charID) database, err := db.GetDB()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.Exec("DELETE FROM gacha_box WHERE gacha_id = $1 AND character_id = $2", pkt.GachaID, s.CharID)
DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfExchangeFpoint2Item(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeFpoint2Item(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfExchangeFpoint2Item) pkt := p.(*mhfpacket.MsgMhfExchangeFpoint2Item)
var balance uint32 var balance uint32
var itemValue, quantity int var itemValue, quantity int
s.server.db.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", pkt.TradeID).Scan(&quantity, &itemValue) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", pkt.TradeID).Scan(&quantity, &itemValue)
cost := (int(pkt.Quantity) * quantity) * itemValue cost := (int(pkt.Quantity) * quantity) * itemValue
s.server.db.QueryRow("UPDATE users u SET frontier_points=frontier_points::int - $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2) RETURNING frontier_points", cost, s.charID).Scan(&balance) database.QueryRow("UPDATE users u SET frontier_points=frontier_points::int - $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2) RETURNING frontier_points", cost, s.CharID).Scan(&balance)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(balance) bf.WriteUint32(balance)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfExchangeItem2Fpoint(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeItem2Fpoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfExchangeItem2Fpoint) pkt := p.(*mhfpacket.MsgMhfExchangeItem2Fpoint)
var balance uint32 var balance uint32
var itemValue, quantity int var itemValue, quantity int
s.server.db.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", pkt.TradeID).Scan(&quantity, &itemValue) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", pkt.TradeID).Scan(&quantity, &itemValue)
cost := (int(pkt.Quantity) / quantity) * itemValue cost := (int(pkt.Quantity) / quantity) * itemValue
s.server.db.QueryRow("UPDATE users u SET frontier_points=COALESCE(frontier_points::int + $1, $1) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2) RETURNING frontier_points", cost, s.charID).Scan(&balance) database.QueryRow("UPDATE users u SET frontier_points=COALESCE(frontier_points::int + $1, $1) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2) RETURNING frontier_points", cost, s.CharID).Scan(&balance)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(balance) bf.WriteUint32(balance)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
type FPointExchange struct { type FPointExchange struct {
@@ -695,7 +769,11 @@ func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {
var exchange FPointExchange var exchange FPointExchange
var exchanges []FPointExchange var exchanges []FPointExchange
var buyables uint16 var buyables uint16
rows, err := s.server.db.Queryx(`SELECT id, item_type, item_id, quantity, fpoints, buyable FROM fpoint_items ORDER BY buyable DESC`) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, err := database.Queryx(`SELECT id, item_type, item_id, quantity, fpoints, buyable FROM fpoint_items ORDER BY buyable DESC`)
if err == nil { if err == nil {
for rows.Next() { for rows.Next() {
err = rows.StructScan(&exchange) err = rows.StructScan(&exchange)
@@ -708,7 +786,7 @@ func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {
exchanges = append(exchanges, exchange) exchanges = append(exchanges, exchange)
} }
} }
if _config.ErupeConfig.ClientID <= _config.Z2 { if config.GetConfig().ClientID <= config.Z2 {
bf.WriteUint8(uint8(len(exchanges))) bf.WriteUint8(uint8(len(exchanges)))
bf.WriteUint8(uint8(buyables)) bf.WriteUint8(uint8(buyables))
} else { } else {
@@ -726,12 +804,12 @@ func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(e.FPoints) bf.WriteUint16(e.FPoints)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfPlayFreeGacha(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPlayFreeGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayFreeGacha) pkt := p.(*mhfpacket.MsgMhfPlayFreeGacha)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(1) bf.WriteUint32(1)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -14,38 +14,38 @@ import (
func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCreateStage) pkt := p.(*mhfpacket.MsgSysCreateStage)
s.server.Lock() s.Server.Lock()
defer s.server.Unlock() defer s.Server.Unlock()
if _, exists := s.server.stages[pkt.StageID]; exists { if _, exists := s.Server.stages[pkt.StageID]; exists {
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} else { } else {
stage := NewStage(pkt.StageID) stage := NewStage(pkt.StageID)
stage.host = s stage.host = s
stage.maxPlayers = uint16(pkt.PlayerCount) stage.maxPlayers = uint16(pkt.PlayerCount)
s.server.stages[stage.id] = stage s.Server.stages[stage.id] = stage
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
} }
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
func doStageTransfer(s *Session, ackHandle uint32, stageID string) { func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
s.server.Lock() s.Server.Lock()
stage, exists := s.server.stages[stageID] stage, exists := s.Server.stages[stageID]
s.server.Unlock() s.Server.Unlock()
if exists { if exists {
stage.Lock() stage.Lock()
stage.clients[s] = s.charID stage.clients[s] = s.CharID
stage.Unlock() stage.Unlock()
} else { // Create new stage object } else { // Create new stage object
s.server.Lock() s.Server.Lock()
s.server.stages[stageID] = NewStage(stageID) s.Server.stages[stageID] = NewStage(stageID)
stage = s.server.stages[stageID] stage = s.Server.stages[stageID]
s.server.Unlock() s.Server.Unlock()
stage.Lock() stage.Lock()
stage.host = s stage.host = s
stage.clients[s] = s.charID stage.clients[s] = s.CharID
stage.Unlock() stage.Unlock()
} }
@@ -56,14 +56,14 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
// Save our new stage ID and pointer to the new stage itself. // Save our new stage ID and pointer to the new stage itself.
s.Lock() s.Lock()
s.stage = s.server.stages[stageID] s.stage = s.Server.stages[stageID]
s.Unlock() s.Unlock()
// Tell the client to cleanup its current stage objects. // Tell the client to cleanup its current stage objects.
s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{}) s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{})
// Confirm the stage entry. // Confirm the stage entry.
doAckSimpleSucceed(s, ackHandle, []byte{0x00, 0x00, 0x00, 0x00}) DoAckSimpleSucceed(s, ackHandle, []byte{0x00, 0x00, 0x00, 0x00})
var temp mhfpacket.MHFPacket var temp mhfpacket.MHFPacket
@@ -71,15 +71,15 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
if !s.userEnteredStage { if !s.userEnteredStage {
s.userEnteredStage = true s.userEnteredStage = true
for _, session := range s.server.sessions { for _, session := range s.Server.sessions {
if s == session { if s == session {
continue continue
} }
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} temp = &mhfpacket.MsgSysInsertUser{CharID: session.CharID}
s.QueueSendMHF(temp) s.QueueSendMHF(temp)
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{ temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID, CharID: session.CharID,
BinaryType: uint8(i + 1), BinaryType: uint8(i + 1),
} }
s.QueueSendMHF(temp) s.QueueSendMHF(temp)
@@ -89,10 +89,10 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
if s.stage != nil { // avoids lock up when using bed for dream quests if s.stage != nil { // avoids lock up when using bed for dream quests
// Notify the client to duplicate the existing objects. // Notify the client to duplicate the existing objects.
s.logger.Info(fmt.Sprintf("Sending existing stage objects to %s", s.Name)) s.Logger.Info(fmt.Sprintf("Sending existing stage objects to %s", s.Name))
s.stage.RLock() s.stage.RLock()
for _, obj := range s.stage.objects { for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID { if obj.ownerCharID == s.CharID {
continue continue
} }
temp = &mhfpacket.MsgSysDuplicateObject{ temp = &mhfpacket.MsgSysDuplicateObject{
@@ -110,14 +110,14 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
} }
func destructEmptyStages(s *Session) { func destructEmptyStages(s *Session) {
s.server.Lock() s.Server.Lock()
defer s.server.Unlock() defer s.Server.Unlock()
for _, stage := range s.server.stages { for _, stage := range s.Server.stages {
// Destroy empty Quest/My series/Guild stages. // Destroy empty Quest/My series/Guild stages.
if stage.id[3:5] == "Qs" || stage.id[3:5] == "Ms" || stage.id[3:5] == "Gs" || stage.id[3:5] == "Ls" { if stage.id[3:5] == "Qs" || stage.id[3:5] == "Ms" || stage.id[3:5] == "Gs" || stage.id[3:5] == "Ls" {
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
delete(s.server.stages, stage.id) delete(s.Server.stages, stage.id)
s.logger.Debug("Destructed stage", zap.String("stage.id", stage.id)) s.Logger.Debug("Destructed stage", zap.String("stage.id", stage.id))
} }
} }
} }
@@ -128,9 +128,9 @@ func removeSessionFromStage(s *Session) {
delete(s.stage.clients, s) delete(s.stage.clients, s)
// Delete old stage objects owned by the client. // Delete old stage objects owned by the client.
s.logger.Info("Sending notification to old stage clients") s.Logger.Info("Sending notification to old stage clients")
for _, object := range s.stage.objects { for _, object := range s.stage.objects {
if object.ownerCharID == s.charID { if object.ownerCharID == s.CharID {
s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ObjID: object.id}, s) s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ObjID: object.id}, s)
delete(s.stage.objects, object.ownerCharID) delete(s.stage.objects, object.ownerCharID)
} }
@@ -140,8 +140,8 @@ func removeSessionFromStage(s *Session) {
} }
func isStageFull(s *Session, StageID string) bool { func isStageFull(s *Session, StageID string) bool {
if stage, exists := s.server.stages[StageID]; exists { if stage, exists := s.Server.stages[StageID]; exists {
if _, exists := stage.reservedClientSlots[s.charID]; exists { if _, exists := stage.reservedClientSlots[s.CharID]; exists {
return false return false
} }
return len(stage.reservedClientSlots)+len(stage.clients) >= int(stage.maxPlayers) return len(stage.reservedClientSlots)+len(stage.clients) >= int(stage.maxPlayers)
@@ -153,14 +153,14 @@ func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysEnterStage) pkt := p.(*mhfpacket.MsgSysEnterStage)
if isStageFull(s, pkt.StageID) { if isStageFull(s, pkt.StageID) {
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01}) DoAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
return return
} }
// Push our current stage ID to the movement stack before entering another one. // Push our current stage ID to the movement stack before entering another one.
if s.stage != nil { if s.stage != nil {
s.stage.Lock() s.stage.Lock()
s.stage.reservedClientSlots[s.charID] = false s.stage.reservedClientSlots[s.CharID] = false
s.stage.Unlock() s.stage.Unlock()
s.stageMoveStack.Push(s.stage.id) s.stageMoveStack.Push(s.stage.id)
} }
@@ -183,16 +183,16 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
if isStageFull(s, backStage) { if isStageFull(s, backStage) {
s.stageMoveStack.Push(backStage) s.stageMoveStack.Push(backStage)
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01}) DoAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
return return
} }
if _, exists := s.stage.reservedClientSlots[s.charID]; exists { if _, exists := s.stage.reservedClientSlots[s.CharID]; exists {
delete(s.stage.reservedClientSlots, s.charID) delete(s.stage.reservedClientSlots, s.CharID)
} }
if _, exists := s.server.stages[backStage].reservedClientSlots[s.charID]; exists { if _, exists := s.Server.stages[backStage].reservedClientSlots[s.CharID]; exists {
delete(s.server.stages[backStage].reservedClientSlots, s.charID) delete(s.Server.stages[backStage].reservedClientSlots, s.CharID)
} }
doStageTransfer(s, pkt.AckHandle, backStage) doStageTransfer(s, pkt.AckHandle, backStage)
@@ -202,7 +202,7 @@ func handleMsgSysMoveStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysMoveStage) pkt := p.(*mhfpacket.MsgSysMoveStage)
if isStageFull(s, pkt.StageID) { if isStageFull(s, pkt.StageID) {
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01}) DoAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
return return
} }
@@ -213,12 +213,12 @@ func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLockStage) pkt := p.(*mhfpacket.MsgSysLockStage)
if stage, exists := s.server.stages[pkt.StageID]; exists { if stage, exists := s.Server.stages[pkt.StageID]; exists {
stage.Lock() stage.Lock()
stage.locked = true stage.locked = true
stage.Unlock() stage.Unlock()
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
@@ -227,13 +227,13 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
defer s.reservationStage.RUnlock() defer s.reservationStage.RUnlock()
for charID := range s.reservationStage.reservedClientSlots { for charID := range s.reservationStage.reservedClientSlots {
session := s.server.FindSessionByCharID(charID) session := s.Server.FindSessionByCharID(charID)
if session != nil { if session != nil {
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
} }
} }
delete(s.server.stages, s.reservationStage.id) delete(s.Server.stages, s.reservationStage.id)
} }
destructEmptyStages(s) destructEmptyStages(s)
@@ -241,40 +241,40 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysReserveStage) pkt := p.(*mhfpacket.MsgSysReserveStage)
if stage, exists := s.server.stages[pkt.StageID]; exists { if stage, exists := s.Server.stages[pkt.StageID]; exists {
stage.Lock() stage.Lock()
defer stage.Unlock() defer stage.Unlock()
if _, exists := stage.reservedClientSlots[s.charID]; exists { if _, exists := stage.reservedClientSlots[s.CharID]; exists {
switch pkt.Ready { switch pkt.Ready {
case 1: // 0x01 case 1: // 0x01
stage.reservedClientSlots[s.charID] = false stage.reservedClientSlots[s.CharID] = false
case 17: // 0x11 case 17: // 0x11
stage.reservedClientSlots[s.charID] = true stage.reservedClientSlots[s.CharID] = true
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else if uint16(len(stage.reservedClientSlots)) < stage.maxPlayers { } else if uint16(len(stage.reservedClientSlots)) < stage.maxPlayers {
if stage.locked { if stage.locked {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
if len(stage.password) > 0 { if len(stage.password) > 0 {
if stage.password != s.stagePass { if stage.password != s.stagePass {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
stage.reservedClientSlots[s.charID] = false stage.reservedClientSlots[s.CharID] = false
// Save the reservation stage in the session for later use in MsgSysUnreserveStage. // Save the reservation stage in the session for later use in MsgSysUnreserveStage.
s.Lock() s.Lock()
s.reservationStage = stage s.reservationStage = stage
s.Unlock() s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} }
} else { } else {
s.logger.Error("Failed to get stage", zap.String("StageID", pkt.StageID)) s.Logger.Error("Failed to get stage", zap.String("StageID", pkt.StageID))
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} }
} }
@@ -285,8 +285,8 @@ func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {
s.Unlock() s.Unlock()
if stage != nil { if stage != nil {
stage.Lock() stage.Lock()
if _, exists := stage.reservedClientSlots[s.charID]; exists { if _, exists := stage.reservedClientSlots[s.CharID]; exists {
delete(stage.reservedClientSlots, s.charID) delete(stage.reservedClientSlots, s.CharID)
} }
stage.Unlock() stage.Unlock()
} }
@@ -300,7 +300,7 @@ func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {
if stage != nil { if stage != nil {
stage.Lock() stage.Lock()
// Will only exist if host. // Will only exist if host.
if _, exists := stage.reservedClientSlots[s.charID]; exists { if _, exists := stage.reservedClientSlots[s.CharID]; exists {
stage.password = pkt.Password stage.password = pkt.Password
} }
stage.Unlock() stage.Unlock()
@@ -314,78 +314,78 @@ func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysSetStageBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysSetStageBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysSetStageBinary) pkt := p.(*mhfpacket.MsgSysSetStageBinary)
if stage, exists := s.server.stages[pkt.StageID]; exists { if stage, exists := s.Server.stages[pkt.StageID]; exists {
stage.Lock() stage.Lock()
stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] = pkt.RawDataPayload stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] = pkt.RawDataPayload
stage.Unlock() stage.Unlock()
} else { } else {
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID)) s.Logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
} }
} }
func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysGetStageBinary) pkt := p.(*mhfpacket.MsgSysGetStageBinary)
if stage, exists := s.server.stages[pkt.StageID]; exists { if stage, exists := s.Server.stages[pkt.StageID]; exists {
stage.Lock() stage.Lock()
if binaryData, exists := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]; exists { if binaryData, exists := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]; exists {
doAckBufSucceed(s, pkt.AckHandle, binaryData) DoAckBufSucceed(s, pkt.AckHandle, binaryData)
} else if pkt.BinaryType1 == 4 { } else if pkt.BinaryType1 == 4 {
// Unknown binary type that is supposedly generated server side // Unknown binary type that is supposedly generated server side
// Temporary response // Temporary response
doAckBufSucceed(s, pkt.AckHandle, []byte{}) DoAckBufSucceed(s, pkt.AckHandle, []byte{})
} else { } else {
s.logger.Warn("Failed to get stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1)) s.Logger.Warn("Failed to get stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1))
s.logger.Warn("Sending blank stage binary") s.Logger.Warn("Sending blank stage binary")
doAckBufSucceed(s, pkt.AckHandle, []byte{}) DoAckBufSucceed(s, pkt.AckHandle, []byte{})
} }
stage.Unlock() stage.Unlock()
} else { } else {
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID)) s.Logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
} }
s.logger.Debug("MsgSysGetStageBinary Done!") s.Logger.Debug("MsgSysGetStageBinary Done!")
} }
func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysWaitStageBinary) pkt := p.(*mhfpacket.MsgSysWaitStageBinary)
if stage, exists := s.server.stages[pkt.StageID]; exists { if stage, exists := s.Server.stages[pkt.StageID]; exists {
if pkt.BinaryType0 == 1 && pkt.BinaryType1 == 12 { if pkt.BinaryType0 == 1 && pkt.BinaryType1 == 12 {
// This might contain the hunter count, or max player count? // This might contain the hunter count, or max player count?
doAckBufSucceed(s, pkt.AckHandle, []byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) DoAckBufSucceed(s, pkt.AckHandle, []byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
return return
} }
for { for {
s.logger.Debug("MsgSysWaitStageBinary before lock and get stage") s.Logger.Debug("MsgSysWaitStageBinary before lock and get stage")
stage.Lock() stage.Lock()
stageBinary, gotBinary := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] stageBinary, gotBinary := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
stage.Unlock() stage.Unlock()
s.logger.Debug("MsgSysWaitStageBinary after lock and get stage") s.Logger.Debug("MsgSysWaitStageBinary after lock and get stage")
if gotBinary { if gotBinary {
doAckBufSucceed(s, pkt.AckHandle, stageBinary) DoAckBufSucceed(s, pkt.AckHandle, stageBinary)
break break
} else { } else {
s.logger.Debug("Waiting stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1)) s.Logger.Debug("Waiting stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1))
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
continue continue
} }
} }
} else { } else {
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID)) s.Logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
} }
s.logger.Debug("MsgSysWaitStageBinary Done!") s.Logger.Debug("MsgSysWaitStageBinary Done!")
} }
func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysEnumerateStage) pkt := p.(*mhfpacket.MsgSysEnumerateStage)
// Read-lock the server stage map. // Read-lock the server stage map.
s.server.stagesLock.RLock() s.Server.stagesLock.RLock()
defer s.server.stagesLock.RUnlock() defer s.Server.stagesLock.RUnlock()
// Build the response // Build the response
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var joinable uint16 var joinable uint16
bf.WriteUint16(0) bf.WriteUint16(0)
for sid, stage := range s.server.stages { for sid, stage := range s.Server.stages {
stage.RLock() stage.RLock()
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
@@ -420,5 +420,5 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
bf.Seek(0, 0) bf.Seek(0, 0)
bf.WriteUint16(joinable) bf.WriteUint16(joinable)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

File diff suppressed because one or more lines are too long

View File

@@ -103,12 +103,12 @@ func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {
} }
} }
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) pkt := p.(*mhfpacket.MsgMhfEntryTournament)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
type TournamentReward struct { type TournamentReward struct {
@@ -127,5 +127,5 @@ func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(reward.Unk1) bf.WriteUint16(reward.Unk1)
bf.WriteUint16(reward.Unk2) bf.WriteUint16(reward.Unk2)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) DoAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -1,7 +1,7 @@
package channelserver package channelserver
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@@ -10,6 +10,7 @@ import (
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
) )
@@ -59,15 +60,18 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
History: []TowerInfoHistory{{make([]int16, 5), make([]int16, 5)}}, History: []TowerInfoHistory{{make([]int16, 5), make([]int16, 5)}},
Level: []TowerInfoLevel{{0, 0, 0, 0}, {0, 0, 0, 0}}, Level: []TowerInfoLevel{{0, 0, 0, 0}, {0, 0, 0, 0}},
} }
database, err := db.GetDB()
var tempSkills string
err := s.server.db.QueryRow(`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), COALESCE(skills, $1) FROM tower WHERE char_id=$2
`, EmptyTowerCSV(64), 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 {
s.server.db.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, s.charID) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var tempSkills string
err = database.QueryRow(`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), COALESCE(skills, $1) FROM tower WHERE char_id=$2
`, EmptyTowerCSV(64), 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 {
database.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, s.CharID)
} }
if _config.ErupeConfig.ClientID <= _config.G7 { if config.GetConfig().ClientID <= config.G7 {
towerInfo.Level = towerInfo.Level[:1] towerInfo.Level = towerInfo.Level[:1]
} }
@@ -113,14 +117,14 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
data = append(data, bf) data = append(data, bf)
} }
} }
doAckEarthSucceed(s, pkt.AckHandle, data) 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)
if s.server.erupeConfig.DebugOptions.QuestTools { if config.GetConfig().DebugOptions.QuestTools {
s.logger.Debug( s.Logger.Debug(
p.Opcode().String(), p.Opcode().String(),
zap.Uint32("InfoType", pkt.InfoType), zap.Uint32("InfoType", pkt.InfoType),
zap.Uint32("Unk1", pkt.Unk1), zap.Uint32("Unk1", pkt.Unk1),
@@ -134,17 +138,20 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
zap.Int64("Unk9", pkt.Unk9), zap.Int64("Unk9", pkt.Unk9),
) )
} }
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch pkt.InfoType { switch pkt.InfoType {
case 2: case 2:
var skills string var skills string
s.server.db.QueryRow(`SELECT COALESCE(skills, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(64), s.charID).Scan(&skills) database.QueryRow(`SELECT COALESCE(skills, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(64), 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) database.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 1, 7: case 1, 7:
// This might give too much TSP? No idea what the rate is supposed to be // This might give too much TSP? No idea what the rate is supposed to be
s.server.db.Exec(`UPDATE tower SET tr=$1, trp=COALESCE(trp, 0)+$2, tsp=COALESCE(tsp, 0)+$3, block1=COALESCE(block1, 0)+$4 WHERE char_id=$5`, pkt.TR, pkt.TRP, pkt.Cost, pkt.Block1, s.charID) database.Exec(`UPDATE tower SET tr=$1, trp=COALESCE(trp, 0)+$2, tsp=COALESCE(tsp, 0)+$3, block1=COALESCE(block1, 0)+$4 WHERE char_id=$5`, pkt.TR, pkt.TRP, pkt.Cost, pkt.Block1, s.CharID)
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
// Default missions // Default missions
@@ -250,7 +257,10 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
Data: tenrouiraiData, Data: tenrouiraiData,
Ticket: []TenrouiraiTicket{{0, 0, 0}}, Ticket: []TenrouiraiTicket{{0, 0, 0}},
} }
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch pkt.Unk1 { switch pkt.Unk1 {
case 1: case 1:
for _, tdata := range tenrouirai.Data { for _, tdata := range tenrouirai.Data {
@@ -284,8 +294,8 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
data = append(data, bf) data = append(data, bf)
} }
case 4: case 4:
s.server.db.QueryRow(`SELECT tower_mission_page FROM guilds WHERE id=$1`, pkt.GuildID).Scan(&tenrouirai.Progress[0].Page) database.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 database.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) `, 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 { if tenrouirai.Progress[0].Mission1 > tenrouiraiData[(tenrouirai.Progress[0].Page*3)-3].Goal {
@@ -313,7 +323,7 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
pkt.Unk3 = 3 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) rows, _ := database.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() { for rows.Next() {
temp := TenrouiraiCharScore{} temp := TenrouiraiCharScore{}
rows.Scan(&temp.Name, &temp.Score) rows.Scan(&temp.Name, &temp.Score)
@@ -326,7 +336,7 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
data = append(data, bf) data = append(data, bf)
} }
case 6: case 6:
s.server.db.QueryRow(`SELECT tower_rp FROM guilds WHERE id=$1`, pkt.GuildID).Scan(&tenrouirai.Ticket[0].RP) database.QueryRow(`SELECT tower_rp FROM guilds WHERE id=$1`, pkt.GuildID).Scan(&tenrouirai.Ticket[0].RP)
for _, ticket := range tenrouirai.Ticket { for _, ticket := range tenrouirai.Ticket {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint8(ticket.Unk0) bf.WriteUint8(ticket.Unk0)
@@ -336,14 +346,17 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
} }
} }
doAckEarthSucceed(s, pkt.AckHandle, data) 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)
database, err := db.GetDB()
if s.server.erupeConfig.DebugOptions.QuestTools { if err != nil {
s.logger.Debug( s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if config.GetConfig().DebugOptions.QuestTools {
s.Logger.Debug(
p.Opcode().String(), p.Opcode().String(),
zap.Uint8("Unk0", pkt.Unk0), zap.Uint8("Unk0", pkt.Unk0),
zap.Uint8("Op", pkt.Op), zap.Uint8("Op", pkt.Op),
@@ -360,7 +373,7 @@ func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
if pkt.Op == 2 { if pkt.Op == 2 {
var page, requirement, donated int 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) database.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++ { for i := 0; i < (page*3)+1; i++ {
requirement += int(tenrouiraiData[i].Cost) requirement += int(tenrouiraiData[i].Cost)
@@ -368,24 +381,24 @@ func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
sd, err := GetCharacterSaveData(s, s.charID) sd, err := GetCharacterSaveData(s, s.CharID)
if err == nil && sd != nil { if err == nil && sd != nil {
sd.RP -= pkt.DonatedRP sd.RP -= pkt.DonatedRP
sd.Save(s) sd.Save(s)
if donated+int(pkt.DonatedRP) >= requirement { 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) database.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) database.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) pkt.DonatedRP = uint16(requirement - donated)
} }
bf.WriteUint32(uint32(pkt.DonatedRP)) bf.WriteUint32(uint32(pkt.DonatedRP))
s.server.db.Exec(`UPDATE guilds SET tower_rp=tower_rp+$1 WHERE id=$2`, pkt.DonatedRP, pkt.GuildID) database.Exec(`UPDATE guilds SET tower_rp=tower_rp+$1 WHERE id=$2`, pkt.DonatedRP, pkt.GuildID)
} else { } else {
bf.WriteUint32(0) bf.WriteUint32(0)
} }
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) DoAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} else { } else {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
} }
@@ -405,7 +418,7 @@ func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(0) bf.WriteInt32(0)
bf.WriteInt32(0) bf.WriteInt32(0)
*/ */
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
type GemInfo struct { type GemInfo struct {
@@ -425,9 +438,12 @@ func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
var data []*byteframe.ByteFrame var data []*byteframe.ByteFrame
gemInfo := []GemInfo{} gemInfo := []GemInfo{}
gemHistory := []GemHistory{} gemHistory := []GemHistory{}
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var tempGems string var tempGems string
s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.charID).Scan(&tempGems) database.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.CharID).Scan(&tempGems)
for i, v := range stringsupport.CSVElems(tempGems) { for i, v := range stringsupport.CSVElems(tempGems) {
gemInfo = append(gemInfo, GemInfo{uint16((i / 5 << 8) + (i%5 + 1)), uint16(v)}) gemInfo = append(gemInfo, GemInfo{uint16((i / 5 << 8) + (i%5 + 1)), uint16(v)})
} }
@@ -450,14 +466,14 @@ func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
data = append(data, bf) data = append(data, bf)
} }
} }
doAckEarthSucceed(s, pkt.AckHandle, data) DoAckEarthSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostGemInfo) pkt := p.(*mhfpacket.MsgMhfPostGemInfo)
if s.server.erupeConfig.DebugOptions.QuestTools { if config.GetConfig().DebugOptions.QuestTools {
s.logger.Debug( s.Logger.Debug(
p.Opcode().String(), p.Opcode().String(),
zap.Uint32("Op", pkt.Op), zap.Uint32("Op", pkt.Op),
zap.Uint32("Unk1", pkt.Unk1), zap.Uint32("Unk1", pkt.Unk1),
@@ -468,25 +484,28 @@ func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {
zap.Int32("Unk6", pkt.Unk6), zap.Int32("Unk6", pkt.Unk6),
) )
} }
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var gems string var gems string
s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.charID).Scan(&gems) database.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.CharID).Scan(&gems)
switch pkt.Op { switch pkt.Op {
case 1: // Add gem case 1: // Add gem
i := int((pkt.Gem >> 8 * 5) + (pkt.Gem - pkt.Gem&0xFF00 - 1%5)) i := int((pkt.Gem >> 8 * 5) + (pkt.Gem - pkt.Gem&0xFF00 - 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) database.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 case 2: // Transfer gem
// no way im doing this for now // no way im doing this for now
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetNotice(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetNotice(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetNotice) pkt := p.(*mhfpacket.MsgMhfGetNotice)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostNotice) pkt := p.(*mhfpacket.MsgMhfPostNotice)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) DoAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/db"
) )
func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {}
@@ -12,44 +13,50 @@ func handleMsgSysDeleteUser(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysSetUserBinary) pkt := p.(*mhfpacket.MsgSysSetUserBinary)
s.server.userBinaryPartsLock.Lock() s.Server.userBinaryPartsLock.Lock()
s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: pkt.BinaryType}] = pkt.RawDataPayload s.Server.userBinaryParts[userBinaryPartID{charID: s.CharID, index: pkt.BinaryType}] = pkt.RawDataPayload
s.server.userBinaryPartsLock.Unlock() s.Server.userBinaryPartsLock.Unlock()
database, err := db.GetDB()
var exists []byte
err := s.server.db.QueryRow("SELECT type2 FROM user_binary WHERE id=$1", s.charID).Scan(&exists)
if err != nil { if err != nil {
s.server.db.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.charID) s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var exists []byte
err = database.QueryRow("SELECT type2 FROM user_binary WHERE id=$1", s.CharID).Scan(&exists)
if err != nil {
database.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.CharID)
} }
s.server.db.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID) database.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.CharID)
msg := &mhfpacket.MsgSysNotifyUserBinary{ msg := &mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID, CharID: s.CharID,
BinaryType: pkt.BinaryType, BinaryType: pkt.BinaryType,
} }
s.server.BroadcastMHF(msg, s) s.Server.BroadcastMHF(msg, s)
} }
func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysGetUserBinary) pkt := p.(*mhfpacket.MsgSysGetUserBinary)
// Try to get the data. // Try to get the data.
s.server.userBinaryPartsLock.RLock() s.Server.userBinaryPartsLock.RLock()
defer s.server.userBinaryPartsLock.RUnlock() defer s.Server.userBinaryPartsLock.RUnlock()
data, ok := s.server.userBinaryParts[userBinaryPartID{charID: pkt.CharID, index: pkt.BinaryType}] data, ok := s.Server.userBinaryParts[userBinaryPartID{charID: pkt.CharID, index: pkt.BinaryType}]
database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
// If we can't get the real data, try to get it from the database. // If we can't get the real data, try to get it from the database.
if !ok { if !ok {
err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binary WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data) err = database.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binary WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) DoAckBufFail(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, data) DoAckBufSucceed(s, pkt.AckHandle, data)
} }
} }

View File

@@ -10,7 +10,7 @@ import (
) )
// BroadcastMHF queues a MHFPacket to be sent to all sessions. // BroadcastMHF queues a MHFPacket to be sent to all sessions.
func (server *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { func (server *ChannelServer) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
// Broadcast the data. // Broadcast the data.
server.Lock() server.Lock()
defer server.Unlock() defer server.Unlock()
@@ -22,7 +22,7 @@ func (server *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Sess
} }
} }
func (server *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session, ignoredChannel *Server) { func (server *ChannelServer) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session, ignoredChannel *ChannelServer) {
for _, c := range server.Channels { for _, c := range server.Channels {
if c == ignoredChannel { if c == ignoredChannel {
continue continue
@@ -32,7 +32,7 @@ func (server *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Sess
} }
// BroadcastChatMessage broadcasts a simple chat message to all the sessions. // BroadcastChatMessage broadcasts a simple chat message to all the sessions.
func (server *Server) BroadcastChatMessage(message string) { func (server *ChannelServer) BroadcastChatMessage(message string) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.SetLE() bf.SetLE()
msgBinChat := &binpacket.MsgBinChat{ msgBinChat := &binpacket.MsgBinChat{
@@ -50,7 +50,7 @@ func (server *Server) BroadcastChatMessage(message string) {
}, nil) }, nil)
} }
func (server *Server) BroadcastRaviente(ip uint32, port uint16, stage []byte, _type uint8) { func (server *ChannelServer) BroadcastRaviente(ip uint32, port uint16, stage []byte, _type uint8) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.SetLE() bf.SetLE()
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk

View File

@@ -6,21 +6,19 @@ import (
"sync" "sync"
"time" "time"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/server/discordbot" "erupe-ce/server/discordbot"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
) )
// Config struct allows configuring the server. // Config struct allows configuring the server.
type Config struct { type Config struct {
ID uint16 ID uint16
DB *sqlx.DB
DiscordBot *discordbot.DiscordBot DiscordBot *discordbot.DiscordBot
ErupeConfig *_config.Config
Name string Name string
Enable bool Enable bool
} }
@@ -31,17 +29,16 @@ type userBinaryPartID struct {
index uint8 index uint8
} }
// Server is a MHF channel server. // ChannelServer is a MHF channel server.
type Server struct { type ChannelServer struct {
sync.Mutex sync.Mutex
Channels []*Server Channels []*ChannelServer
ID uint16 ID uint16
GlobalID string GlobalID string
IP string IP string
Port uint16 Port uint16
logger logger.Logger logger logger.Logger
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
@@ -76,7 +73,7 @@ type Server struct {
} }
// NewServer creates a new Server type. // NewServer creates a new Server type.
func NewServer(config *Config) *Server { func NewServer(config *Config) *ChannelServer {
stageNames := []string{ stageNames := []string{
"sl1Ns200p0a0u0", // Mezeporta "sl1Ns200p0a0u0", // Mezeporta
"sl1Ns211p0a0u0", // Rasta bar "sl1Ns211p0a0u0", // Rasta bar
@@ -90,11 +87,9 @@ func NewServer(config *Config) *Server {
for _, name := range stageNames { for _, name := range stageNames {
stages[name] = NewStage(name) stages[name] = NewStage(name)
} }
server := &Server{ server := &ChannelServer{
ID: config.ID, ID: config.ID,
logger: logger.Get().Named("channel-" + fmt.Sprint(config.ID)), logger: logger.Get().Named("channel-" + fmt.Sprint(config.ID)),
db: config.DB,
erupeConfig: config.ErupeConfig,
acceptConns: make(chan net.Conn), acceptConns: make(chan net.Conn),
deleteConns: make(chan net.Conn), deleteConns: make(chan net.Conn),
sessions: make(map[net.Conn]*Session), sessions: make(map[net.Conn]*Session),
@@ -121,7 +116,7 @@ func NewServer(config *Config) *Server {
} }
// Start starts the server in a new goroutine. // Start starts the server in a new goroutine.
func (server *Server) Start() error { func (server *ChannelServer) Start() error {
l, err := net.Listen("tcp", fmt.Sprintf(":%d", server.Port)) l, err := net.Listen("tcp", fmt.Sprintf(":%d", server.Port))
if err != nil { if err != nil {
return err return err
@@ -130,9 +125,8 @@ func (server *Server) Start() error {
go server.acceptClients() go server.acceptClients()
go server.manageSessions() go server.manageSessions()
// Start the discord bot for chat integration. // Start the discord bot for chat integration.
if server.erupeConfig.Discord.Enabled && server.discordBot != nil { if config.GetConfig().Discord.Enabled && server.discordBot != nil {
server.discordBot.Session.AddHandler(server.onDiscordMessage) server.discordBot.Session.AddHandler(server.onDiscordMessage)
server.discordBot.Session.AddHandler(server.onInteraction) server.discordBot.Session.AddHandler(server.onInteraction)
} }
@@ -141,7 +135,7 @@ func (server *Server) Start() error {
} }
// Shutdown tries to shut down the server gracefully. // Shutdown tries to shut down the server gracefully.
func (server *Server) Shutdown() { func (server *ChannelServer) Shutdown() {
server.Lock() server.Lock()
server.isShuttingDown = true server.isShuttingDown = true
server.Unlock() server.Unlock()
@@ -151,7 +145,7 @@ func (server *Server) Shutdown() {
close(server.acceptConns) close(server.acceptConns)
} }
func (server *Server) acceptClients() { func (server *ChannelServer) acceptClients() {
for { for {
conn, err := server.listener.Accept() conn, err := server.listener.Accept()
if err != nil { if err != nil {
@@ -170,7 +164,7 @@ func (server *Server) acceptClients() {
} }
} }
func (server *Server) manageSessions() { func (server *ChannelServer) manageSessions() {
for { for {
select { select {
case newConn := <-server.acceptConns: case newConn := <-server.acceptConns:
@@ -201,10 +195,10 @@ func (server *Server) manageSessions() {
} }
} }
func (server *Server) FindSessionByCharID(charID uint32) *Session { func (server *ChannelServer) FindSessionByCharID(charID uint32) *Session {
for _, c := range server.Channels { for _, c := range server.Channels {
for _, session := range c.sessions { for _, session := range c.sessions {
if session.charID == charID { if session.CharID == charID {
return session return session
} }
} }
@@ -212,10 +206,14 @@ func (server *Server) FindSessionByCharID(charID uint32) *Session {
return nil return nil
} }
func (server *Server) DisconnectUser(uid uint32) { func (server *ChannelServer) DisconnectUser(uid uint32) {
var cid uint32 var cid uint32
var cids []uint32 var cids []uint32
rows, _ := server.db.Query(`SELECT id FROM characters WHERE user_id=$1`, uid) database, err := db.GetDB()
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
rows, _ := database.Query(`SELECT id FROM characters WHERE user_id=$1`, uid)
for rows.Next() { for rows.Next() {
rows.Scan(&cid) rows.Scan(&cid)
cids = append(cids, cid) cids = append(cids, cid)
@@ -223,7 +221,7 @@ func (server *Server) DisconnectUser(uid uint32) {
for _, c := range server.Channels { for _, c := range server.Channels {
for _, session := range c.sessions { for _, session := range c.sessions {
for _, cid := range cids { for _, cid := range cids {
if session.charID == cid { if session.CharID == cid {
session.rawConn.Close() session.rawConn.Close()
break break
} }
@@ -232,7 +230,7 @@ func (server *Server) DisconnectUser(uid uint32) {
} }
} }
func (server *Server) FindObjectByChar(charID uint32) *Object { func (server *ChannelServer) FindObjectByChar(charID uint32) *Object {
server.stagesLock.RLock() server.stagesLock.RLock()
defer server.stagesLock.RUnlock() defer server.stagesLock.RUnlock()
for _, stage := range server.stages { for _, stage := range server.stages {
@@ -250,7 +248,7 @@ func (server *Server) FindObjectByChar(charID uint32) *Object {
return nil return nil
} }
func (server *Server) HasSemaphore(ses *Session) bool { func (server *ChannelServer) HasSemaphore(ses *Session) bool {
for _, semaphore := range server.semaphore { for _, semaphore := range server.semaphore {
if semaphore.host == ses { if semaphore.host == ses {
return true return true
@@ -259,7 +257,7 @@ func (server *Server) HasSemaphore(ses *Session) bool {
return false return false
} }
func (server *Server) Season() uint8 { func (server *ChannelServer) Season() uint8 {
sid := int64(((server.ID & 0xFF00) - 4096) / 256) sid := int64(((server.ID & 0xFF00) - 4096) / 256)
return uint8(((gametime.TimeAdjusted().Unix() / 86400) + sid) % 3) return uint8(((gametime.TimeAdjusted().Unix() / 86400) + sid) % 3)
} }

View File

@@ -1,6 +1,7 @@
package channelserver package channelserver
import ( import (
"erupe-ce/utils/db"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
@@ -15,7 +16,7 @@ type Player struct {
QuestID int QuestID int
} }
func getPlayerSlice(server *Server) []Player { func getPlayerSlice(server *ChannelServer) []Player {
var p []Player var p []Player
var questIndex int var questIndex int
@@ -40,7 +41,7 @@ func getPlayerSlice(server *Server) []Player {
return p return p
} }
func getCharacterList(server *Server) string { func getCharacterList(server *ChannelServer) string {
questEmojis := []string{ questEmojis := []string{
":person_in_lotus_position:", ":person_in_lotus_position:",
":white_circle:", ":white_circle:",
@@ -69,11 +70,15 @@ func getCharacterList(server *Server) string {
} }
// onInteraction handles slash commands // onInteraction handles slash commands
func (server *Server) onInteraction(ds *discordgo.Session, i *discordgo.InteractionCreate) { func (server *ChannelServer) onInteraction(ds *discordgo.Session, i *discordgo.InteractionCreate) {
database, err := db.GetDB()
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
switch i.Interaction.ApplicationCommandData().Name { switch i.Interaction.ApplicationCommandData().Name {
case "link": case "link":
var temp string var temp string
err := server.db.QueryRow(`UPDATE users SET discord_id = $1 WHERE discord_token = $2 RETURNING discord_id`, i.Member.User.ID, i.ApplicationCommandData().Options[0].StringValue()).Scan(&temp) err := database.QueryRow(`UPDATE users SET discord_id = $1 WHERE discord_token = $2 RETURNING discord_id`, i.Member.User.ID, i.ApplicationCommandData().Options[0].StringValue()).Scan(&temp)
if err == nil { if err == nil {
ds.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ ds.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource, Type: discordgo.InteractionResponseChannelMessageWithSource,
@@ -93,7 +98,7 @@ func (server *Server) onInteraction(ds *discordgo.Session, i *discordgo.Interact
} }
case "password": case "password":
password, _ := bcrypt.GenerateFromPassword([]byte(i.ApplicationCommandData().Options[0].StringValue()), 10) password, _ := bcrypt.GenerateFromPassword([]byte(i.ApplicationCommandData().Options[0].StringValue()), 10)
_, err := server.db.Exec(`UPDATE users SET password = $1 WHERE discord_id = $2`, password, i.Member.User.ID) _, err := database.Exec(`UPDATE users SET password = $1 WHERE discord_id = $2`, password, i.Member.User.ID)
if err == nil { if err == nil {
ds.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ ds.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource, Type: discordgo.InteractionResponseChannelMessageWithSource,
@@ -115,7 +120,7 @@ func (server *Server) onInteraction(ds *discordgo.Session, i *discordgo.Interact
} }
// onDiscordMessage handles receiving messages from discord and forwarding them ingame. // onDiscordMessage handles receiving messages from discord and forwarding them ingame.
func (server *Server) onDiscordMessage(ds *discordgo.Session, m *discordgo.MessageCreate) { func (server *ChannelServer) onDiscordMessage(ds *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages from bots, or messages that are not in the correct channel. // Ignore messages from bots, or messages that are not in the correct channel.
if m.Author.Bot || m.ChannelID != server.erupeConfig.Discord.RelayChannel.RelayChannelID { if m.Author.Bot || m.ChannelID != server.erupeConfig.Discord.RelayChannel.RelayChannelID {
return return
@@ -148,14 +153,14 @@ func (server *Server) onDiscordMessage(ds *discordgo.Session, m *discordgo.Messa
server.BroadcastChatMessage(messages[i]) server.BroadcastChatMessage(messages[i])
} }
} }
func (server *Server) DiscordChannelSend(charName string, content string) { func (server *ChannelServer) DiscordChannelSend(charName string, content string) {
if server.erupeConfig.Discord.Enabled && server.discordBot != nil { if server.erupeConfig.Discord.Enabled && server.discordBot != nil {
message := fmt.Sprintf("**%s**: %s", charName, content) message := fmt.Sprintf("**%s**: %s", charName, content)
server.discordBot.RealtimeChannelSend(message) server.discordBot.RealtimeChannelSend(message)
} }
} }
func (server *Server) DiscordScreenShotSend(charName string, title string, description string, articleToken string) { func (server *ChannelServer) DiscordScreenShotSend(charName string, title string, description string, articleToken string) {
if server.erupeConfig.Discord.Enabled && server.discordBot != nil { if server.erupeConfig.Discord.Enabled && server.discordBot != nil {
imageUrl := fmt.Sprintf("%s:%d/api/ss/bbs/%s", server.erupeConfig.Screenshots.Host, server.erupeConfig.Screenshots.Port, articleToken) imageUrl := fmt.Sprintf("%s:%d/api/ss/bbs/%s", server.erupeConfig.Screenshots.Host, server.erupeConfig.Screenshots.Port, articleToken)
message := fmt.Sprintf("**%s**: %s - %s %s", charName, title, description, imageUrl) message := fmt.Sprintf("**%s**: %s - %s %s", charName, title, description, imageUrl)

View File

@@ -155,14 +155,14 @@ func init() {
handlerTable[network.MSG_MHF_CARAVAN_MY_SCORE] = handleMsgMhfCaravanMyScore handlerTable[network.MSG_MHF_CARAVAN_MY_SCORE] = handleMsgMhfCaravanMyScore
handlerTable[network.MSG_MHF_CARAVAN_RANKING] = handleMsgMhfCaravanRanking handlerTable[network.MSG_MHF_CARAVAN_RANKING] = handleMsgMhfCaravanRanking
handlerTable[network.MSG_MHF_CARAVAN_MY_RANK] = handleMsgMhfCaravanMyRank handlerTable[network.MSG_MHF_CARAVAN_MY_RANK] = handleMsgMhfCaravanMyRank
handlerTable[network.MSG_MHF_CREATE_GUILD] = handleMsgMhfCreateGuild handlerTable[network.MSG_MHF_CREATE_GUILD] = HandleMsgMhfCreateGuild
handlerTable[network.MSG_MHF_OPERATE_GUILD] = handleMsgMhfOperateGuild handlerTable[network.MSG_MHF_OPERATE_GUILD] = HandleMsgMhfOperateGuild
handlerTable[network.MSG_MHF_OPERATE_GUILD_MEMBER] = handleMsgMhfOperateGuildMember handlerTable[network.MSG_MHF_OPERATE_GUILD_MEMBER] = HandleMsgMhfOperateGuildMember
handlerTable[network.MSG_MHF_INFO_GUILD] = handleMsgMhfInfoGuild handlerTable[network.MSG_MHF_INFO_GUILD] = HandleMsgMhfInfoGuild
handlerTable[network.MSG_MHF_ENUMERATE_GUILD] = handleMsgMhfEnumerateGuild handlerTable[network.MSG_MHF_ENUMERATE_GUILD] = HandleMsgMhfEnumerateGuild
handlerTable[network.MSG_MHF_UPDATE_GUILD] = handleMsgMhfUpdateGuild handlerTable[network.MSG_MHF_UPDATE_GUILD] = HandleMsgMhfUpdateGuild
handlerTable[network.MSG_MHF_ARRANGE_GUILD_MEMBER] = handleMsgMhfArrangeGuildMember handlerTable[network.MSG_MHF_ARRANGE_GUILD_MEMBER] = HandleMsgMhfArrangeGuildMember
handlerTable[network.MSG_MHF_ENUMERATE_GUILD_MEMBER] = handleMsgMhfEnumerateGuildMember handlerTable[network.MSG_MHF_ENUMERATE_GUILD_MEMBER] = HandleMsgMhfEnumerateGuildMember
handlerTable[network.MSG_MHF_ENUMERATE_CAMPAIGN] = handleMsgMhfEnumerateCampaign handlerTable[network.MSG_MHF_ENUMERATE_CAMPAIGN] = handleMsgMhfEnumerateCampaign
handlerTable[network.MSG_MHF_STATE_CAMPAIGN] = handleMsgMhfStateCampaign handlerTable[network.MSG_MHF_STATE_CAMPAIGN] = handleMsgMhfStateCampaign
handlerTable[network.MSG_MHF_APPLY_CAMPAIGN] = handleMsgMhfApplyCampaign handlerTable[network.MSG_MHF_APPLY_CAMPAIGN] = handleMsgMhfApplyCampaign
@@ -170,7 +170,7 @@ func init() {
handlerTable[network.MSG_MHF_ACQUIRE_ITEM] = handleMsgMhfAcquireItem handlerTable[network.MSG_MHF_ACQUIRE_ITEM] = handleMsgMhfAcquireItem
handlerTable[network.MSG_MHF_TRANSFER_ITEM] = handleMsgMhfTransferItem handlerTable[network.MSG_MHF_TRANSFER_ITEM] = handleMsgMhfTransferItem
handlerTable[network.MSG_MHF_MERCENARY_HUNTDATA] = handleMsgMhfMercenaryHuntdata handlerTable[network.MSG_MHF_MERCENARY_HUNTDATA] = handleMsgMhfMercenaryHuntdata
handlerTable[network.MSG_MHF_ENTRY_ROOKIE_GUILD] = handleMsgMhfEntryRookieGuild handlerTable[network.MSG_MHF_ENTRY_ROOKIE_GUILD] = HandleMsgMhfEntryRookieGuild
handlerTable[network.MSG_MHF_ENUMERATE_QUEST] = handleMsgMhfEnumerateQuest handlerTable[network.MSG_MHF_ENUMERATE_QUEST] = handleMsgMhfEnumerateQuest
handlerTable[network.MSG_MHF_ENUMERATE_EVENT] = handleMsgMhfEnumerateEvent handlerTable[network.MSG_MHF_ENUMERATE_EVENT] = handleMsgMhfEnumerateEvent
handlerTable[network.MSG_MHF_ENUMERATE_PRICE] = handleMsgMhfEnumeratePrice handlerTable[network.MSG_MHF_ENUMERATE_PRICE] = handleMsgMhfEnumeratePrice
@@ -187,14 +187,14 @@ func init() {
handlerTable[network.MSG_MHF_UPDATE_WAREHOUSE] = handleMsgMhfUpdateWarehouse handlerTable[network.MSG_MHF_UPDATE_WAREHOUSE] = handleMsgMhfUpdateWarehouse
handlerTable[network.MSG_MHF_ACQUIRE_TITLE] = handleMsgMhfAcquireTitle handlerTable[network.MSG_MHF_ACQUIRE_TITLE] = handleMsgMhfAcquireTitle
handlerTable[network.MSG_MHF_ENUMERATE_TITLE] = handleMsgMhfEnumerateTitle handlerTable[network.MSG_MHF_ENUMERATE_TITLE] = handleMsgMhfEnumerateTitle
handlerTable[network.MSG_MHF_ENUMERATE_GUILD_ITEM] = handleMsgMhfEnumerateGuildItem handlerTable[network.MSG_MHF_ENUMERATE_GUILD_ITEM] = HandleMsgMhfEnumerateGuildItem
handlerTable[network.MSG_MHF_UPDATE_GUILD_ITEM] = handleMsgMhfUpdateGuildItem handlerTable[network.MSG_MHF_UPDATE_GUILD_ITEM] = HandleMsgMhfUpdateGuildItem
handlerTable[network.MSG_MHF_ENUMERATE_UNION_ITEM] = handleMsgMhfEnumerateUnionItem handlerTable[network.MSG_MHF_ENUMERATE_UNION_ITEM] = handleMsgMhfEnumerateUnionItem
handlerTable[network.MSG_MHF_UPDATE_UNION_ITEM] = handleMsgMhfUpdateUnionItem handlerTable[network.MSG_MHF_UPDATE_UNION_ITEM] = handleMsgMhfUpdateUnionItem
handlerTable[network.MSG_MHF_CREATE_JOINT] = handleMsgMhfCreateJoint handlerTable[network.MSG_MHF_CREATE_JOINT] = HandleMsgMhfCreateJoint
handlerTable[network.MSG_MHF_OPERATE_JOINT] = handleMsgMhfOperateJoint handlerTable[network.MSG_MHF_OPERATE_JOINT] = HandleMsgMhfOperateJoint
handlerTable[network.MSG_MHF_INFO_JOINT] = handleMsgMhfInfoJoint handlerTable[network.MSG_MHF_INFO_JOINT] = HandleMsgMhfInfoJoint
handlerTable[network.MSG_MHF_UPDATE_GUILD_ICON] = handleMsgMhfUpdateGuildIcon handlerTable[network.MSG_MHF_UPDATE_GUILD_ICON] = HandleMsgMhfUpdateGuildIcon
handlerTable[network.MSG_MHF_INFO_FESTA] = handleMsgMhfInfoFesta handlerTable[network.MSG_MHF_INFO_FESTA] = handleMsgMhfInfoFesta
handlerTable[network.MSG_MHF_ENTRY_FESTA] = handleMsgMhfEntryFesta handlerTable[network.MSG_MHF_ENTRY_FESTA] = handleMsgMhfEntryFesta
handlerTable[network.MSG_MHF_CHARGE_FESTA] = handleMsgMhfChargeFesta handlerTable[network.MSG_MHF_CHARGE_FESTA] = handleMsgMhfChargeFesta
@@ -207,8 +207,8 @@ func init() {
handlerTable[network.MSG_MHF_UPDATE_CAFEPOINT] = handleMsgMhfUpdateCafepoint handlerTable[network.MSG_MHF_UPDATE_CAFEPOINT] = handleMsgMhfUpdateCafepoint
handlerTable[network.MSG_MHF_CHECK_DAILY_CAFEPOINT] = handleMsgMhfCheckDailyCafepoint handlerTable[network.MSG_MHF_CHECK_DAILY_CAFEPOINT] = handleMsgMhfCheckDailyCafepoint
handlerTable[network.MSG_MHF_GET_COG_INFO] = handleMsgMhfGetCogInfo handlerTable[network.MSG_MHF_GET_COG_INFO] = handleMsgMhfGetCogInfo
handlerTable[network.MSG_MHF_CHECK_MONTHLY_ITEM] = handleMsgMhfCheckMonthlyItem handlerTable[network.MSG_MHF_CHECK_MONTHLY_ITEM] = HandleMsgMhfCheckMonthlyItem
handlerTable[network.MSG_MHF_ACQUIRE_MONTHLY_ITEM] = handleMsgMhfAcquireMonthlyItem handlerTable[network.MSG_MHF_ACQUIRE_MONTHLY_ITEM] = HandleMsgMhfAcquireMonthlyItem
handlerTable[network.MSG_MHF_CHECK_WEEKLY_STAMP] = handleMsgMhfCheckWeeklyStamp handlerTable[network.MSG_MHF_CHECK_WEEKLY_STAMP] = handleMsgMhfCheckWeeklyStamp
handlerTable[network.MSG_MHF_EXCHANGE_WEEKLY_STAMP] = handleMsgMhfExchangeWeeklyStamp handlerTable[network.MSG_MHF_EXCHANGE_WEEKLY_STAMP] = handleMsgMhfExchangeWeeklyStamp
handlerTable[network.MSG_MHF_CREATE_MERCENARY] = handleMsgMhfCreateMercenary handlerTable[network.MSG_MHF_CREATE_MERCENARY] = handleMsgMhfCreateMercenary
@@ -238,8 +238,8 @@ func init() {
handlerTable[network.MSG_MHF_GET_MYHOUSE_INFO] = handleMsgMhfGetMyhouseInfo handlerTable[network.MSG_MHF_GET_MYHOUSE_INFO] = handleMsgMhfGetMyhouseInfo
handlerTable[network.MSG_MHF_UPDATE_MYHOUSE_INFO] = handleMsgMhfUpdateMyhouseInfo handlerTable[network.MSG_MHF_UPDATE_MYHOUSE_INFO] = handleMsgMhfUpdateMyhouseInfo
handlerTable[network.MSG_MHF_GET_WEEKLY_SCHEDULE] = handleMsgMhfGetWeeklySchedule handlerTable[network.MSG_MHF_GET_WEEKLY_SCHEDULE] = handleMsgMhfGetWeeklySchedule
handlerTable[network.MSG_MHF_ENUMERATE_INV_GUILD] = handleMsgMhfEnumerateInvGuild handlerTable[network.MSG_MHF_ENUMERATE_INV_GUILD] = HandleMsgMhfEnumerateInvGuild
handlerTable[network.MSG_MHF_OPERATION_INV_GUILD] = handleMsgMhfOperationInvGuild handlerTable[network.MSG_MHF_OPERATION_INV_GUILD] = HandleMsgMhfOperationInvGuild
handlerTable[network.MSG_MHF_STAMPCARD_STAMP] = handleMsgMhfStampcardStamp handlerTable[network.MSG_MHF_STAMPCARD_STAMP] = handleMsgMhfStampcardStamp
handlerTable[network.MSG_MHF_STAMPCARD_PRIZE] = handleMsgMhfStampcardPrize handlerTable[network.MSG_MHF_STAMPCARD_PRIZE] = handleMsgMhfStampcardPrize
handlerTable[network.MSG_MHF_UNRESERVE_SRG] = handleMsgMhfUnreserveSrg handlerTable[network.MSG_MHF_UNRESERVE_SRG] = handleMsgMhfUnreserveSrg
@@ -247,8 +247,8 @@ func init() {
handlerTable[network.MSG_MHF_SAVE_PLATE_DATA] = handleMsgMhfSavePlateData handlerTable[network.MSG_MHF_SAVE_PLATE_DATA] = handleMsgMhfSavePlateData
handlerTable[network.MSG_MHF_LOAD_PLATE_BOX] = handleMsgMhfLoadPlateBox handlerTable[network.MSG_MHF_LOAD_PLATE_BOX] = handleMsgMhfLoadPlateBox
handlerTable[network.MSG_MHF_SAVE_PLATE_BOX] = handleMsgMhfSavePlateBox handlerTable[network.MSG_MHF_SAVE_PLATE_BOX] = handleMsgMhfSavePlateBox
handlerTable[network.MSG_MHF_READ_GUILDCARD] = handleMsgMhfReadGuildcard handlerTable[network.MSG_MHF_READ_GUILDCARD] = HandleMsgMhfReadGuildcard
handlerTable[network.MSG_MHF_UPDATE_GUILDCARD] = handleMsgMhfUpdateGuildcard handlerTable[network.MSG_MHF_UPDATE_GUILDCARD] = HandleMsgMhfUpdateGuildcard
handlerTable[network.MSG_MHF_READ_BEAT_LEVEL] = handleMsgMhfReadBeatLevel handlerTable[network.MSG_MHF_READ_BEAT_LEVEL] = handleMsgMhfReadBeatLevel
handlerTable[network.MSG_MHF_UPDATE_BEAT_LEVEL] = handleMsgMhfUpdateBeatLevel handlerTable[network.MSG_MHF_UPDATE_BEAT_LEVEL] = handleMsgMhfUpdateBeatLevel
handlerTable[network.MSG_MHF_READ_BEAT_LEVEL_ALL_RANKING] = handleMsgMhfReadBeatLevelAllRanking handlerTable[network.MSG_MHF_READ_BEAT_LEVEL_ALL_RANKING] = handleMsgMhfReadBeatLevelAllRanking
@@ -264,38 +264,38 @@ func init() {
handlerTable[network.MSG_MHF_GET_EARTH_STATUS] = handleMsgMhfGetEarthStatus handlerTable[network.MSG_MHF_GET_EARTH_STATUS] = handleMsgMhfGetEarthStatus
handlerTable[network.MSG_MHF_LOAD_PARTNER] = handleMsgMhfLoadPartner handlerTable[network.MSG_MHF_LOAD_PARTNER] = handleMsgMhfLoadPartner
handlerTable[network.MSG_MHF_SAVE_PARTNER] = handleMsgMhfSavePartner handlerTable[network.MSG_MHF_SAVE_PARTNER] = handleMsgMhfSavePartner
handlerTable[network.MSG_MHF_GET_GUILD_MISSION_LIST] = handleMsgMhfGetGuildMissionList handlerTable[network.MSG_MHF_GET_GUILD_MISSION_LIST] = HandleMsgMhfGetGuildMissionList
handlerTable[network.MSG_MHF_GET_GUILD_MISSION_RECORD] = handleMsgMhfGetGuildMissionRecord handlerTable[network.MSG_MHF_GET_GUILD_MISSION_RECORD] = HandleMsgMhfGetGuildMissionRecord
handlerTable[network.MSG_MHF_ADD_GUILD_MISSION_COUNT] = handleMsgMhfAddGuildMissionCount handlerTable[network.MSG_MHF_ADD_GUILD_MISSION_COUNT] = HandleMsgMhfAddGuildMissionCount
handlerTable[network.MSG_MHF_SET_GUILD_MISSION_TARGET] = handleMsgMhfSetGuildMissionTarget handlerTable[network.MSG_MHF_SET_GUILD_MISSION_TARGET] = HandleMsgMhfSetGuildMissionTarget
handlerTable[network.MSG_MHF_CANCEL_GUILD_MISSION_TARGET] = handleMsgMhfCancelGuildMissionTarget handlerTable[network.MSG_MHF_CANCEL_GUILD_MISSION_TARGET] = HandleMsgMhfCancelGuildMissionTarget
handlerTable[network.MSG_MHF_LOAD_OTOMO_AIROU] = handleMsgMhfLoadOtomoAirou handlerTable[network.MSG_MHF_LOAD_OTOMO_AIROU] = handleMsgMhfLoadOtomoAirou
handlerTable[network.MSG_MHF_SAVE_OTOMO_AIROU] = handleMsgMhfSaveOtomoAirou handlerTable[network.MSG_MHF_SAVE_OTOMO_AIROU] = handleMsgMhfSaveOtomoAirou
handlerTable[network.MSG_MHF_ENUMERATE_GUILD_TRESURE] = handleMsgMhfEnumerateGuildTresure handlerTable[network.MSG_MHF_ENUMERATE_GUILD_TRESURE] = HandleMsgMhfEnumerateGuildTresure
handlerTable[network.MSG_MHF_ENUMERATE_AIROULIST] = handleMsgMhfEnumerateAiroulist handlerTable[network.MSG_MHF_ENUMERATE_AIROULIST] = handleMsgMhfEnumerateAiroulist
handlerTable[network.MSG_MHF_REGIST_GUILD_TRESURE] = handleMsgMhfRegistGuildTresure handlerTable[network.MSG_MHF_REGIST_GUILD_TRESURE] = HandleMsgMhfRegistGuildTresure
handlerTable[network.MSG_MHF_ACQUIRE_GUILD_TRESURE] = handleMsgMhfAcquireGuildTresure handlerTable[network.MSG_MHF_ACQUIRE_GUILD_TRESURE] = HandleMsgMhfAcquireGuildTresure
handlerTable[network.MSG_MHF_OPERATE_GUILD_TRESURE_REPORT] = handleMsgMhfOperateGuildTresureReport handlerTable[network.MSG_MHF_OPERATE_GUILD_TRESURE_REPORT] = HandleMsgMhfOperateGuildTresureReport
handlerTable[network.MSG_MHF_GET_GUILD_TRESURE_SOUVENIR] = handleMsgMhfGetGuildTresureSouvenir handlerTable[network.MSG_MHF_GET_GUILD_TRESURE_SOUVENIR] = HandleMsgMhfGetGuildTresureSouvenir
handlerTable[network.MSG_MHF_ACQUIRE_GUILD_TRESURE_SOUVENIR] = handleMsgMhfAcquireGuildTresureSouvenir handlerTable[network.MSG_MHF_ACQUIRE_GUILD_TRESURE_SOUVENIR] = HandleMsgMhfAcquireGuildTresureSouvenir
handlerTable[network.MSG_MHF_ENUMERATE_FESTA_INTERMEDIATE_PRIZE] = handleMsgMhfEnumerateFestaIntermediatePrize handlerTable[network.MSG_MHF_ENUMERATE_FESTA_INTERMEDIATE_PRIZE] = handleMsgMhfEnumerateFestaIntermediatePrize
handlerTable[network.MSG_MHF_ACQUIRE_FESTA_INTERMEDIATE_PRIZE] = handleMsgMhfAcquireFestaIntermediatePrize handlerTable[network.MSG_MHF_ACQUIRE_FESTA_INTERMEDIATE_PRIZE] = handleMsgMhfAcquireFestaIntermediatePrize
handlerTable[network.MSG_MHF_LOAD_DECO_MYSET] = handleMsgMhfLoadDecoMyset handlerTable[network.MSG_MHF_LOAD_DECO_MYSET] = handleMsgMhfLoadDecoMyset
handlerTable[network.MSG_MHF_SAVE_DECO_MYSET] = handleMsgMhfSaveDecoMyset handlerTable[network.MSG_MHF_SAVE_DECO_MYSET] = handleMsgMhfSaveDecoMyset
handlerTable[network.MSG_MHF_reserve10F] = handleMsgMhfReserve10F handlerTable[network.MSG_MHF_reserve10F] = handleMsgMhfReserve10F
handlerTable[network.MSG_MHF_LOAD_GUILD_COOKING] = handleMsgMhfLoadGuildCooking handlerTable[network.MSG_MHF_LOAD_GUILD_COOKING] = HandleMsgMhfLoadGuildCooking
handlerTable[network.MSG_MHF_REGIST_GUILD_COOKING] = handleMsgMhfRegistGuildCooking handlerTable[network.MSG_MHF_REGIST_GUILD_COOKING] = HandleMsgMhfRegistGuildCooking
handlerTable[network.MSG_MHF_LOAD_GUILD_ADVENTURE] = handleMsgMhfLoadGuildAdventure handlerTable[network.MSG_MHF_LOAD_GUILD_ADVENTURE] = HandleMsgMhfLoadGuildAdventure
handlerTable[network.MSG_MHF_REGIST_GUILD_ADVENTURE] = handleMsgMhfRegistGuildAdventure handlerTable[network.MSG_MHF_REGIST_GUILD_ADVENTURE] = HandleMsgMhfRegistGuildAdventure
handlerTable[network.MSG_MHF_ACQUIRE_GUILD_ADVENTURE] = handleMsgMhfAcquireGuildAdventure handlerTable[network.MSG_MHF_ACQUIRE_GUILD_ADVENTURE] = HandleMsgMhfAcquireGuildAdventure
handlerTable[network.MSG_MHF_CHARGE_GUILD_ADVENTURE] = handleMsgMhfChargeGuildAdventure handlerTable[network.MSG_MHF_CHARGE_GUILD_ADVENTURE] = HandleMsgMhfChargeGuildAdventure
handlerTable[network.MSG_MHF_LOAD_LEGEND_DISPATCH] = handleMsgMhfLoadLegendDispatch handlerTable[network.MSG_MHF_LOAD_LEGEND_DISPATCH] = handleMsgMhfLoadLegendDispatch
handlerTable[network.MSG_MHF_LOAD_HUNTER_NAVI] = handleMsgMhfLoadHunterNavi handlerTable[network.MSG_MHF_LOAD_HUNTER_NAVI] = handleMsgMhfLoadHunterNavi
handlerTable[network.MSG_MHF_SAVE_HUNTER_NAVI] = handleMsgMhfSaveHunterNavi handlerTable[network.MSG_MHF_SAVE_HUNTER_NAVI] = handleMsgMhfSaveHunterNavi
handlerTable[network.MSG_MHF_REGIST_SPABI_TIME] = handleMsgMhfRegistSpabiTime handlerTable[network.MSG_MHF_REGIST_SPABI_TIME] = handleMsgMhfRegistSpabiTime
handlerTable[network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_MASTER] = handleMsgMhfGetGuildWeeklyBonusMaster handlerTable[network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_MASTER] = HandleMsgMhfGetGuildWeeklyBonusMaster
handlerTable[network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_ACTIVE_COUNT] = handleMsgMhfGetGuildWeeklyBonusActiveCount handlerTable[network.MSG_MHF_GET_GUILD_WEEKLY_BONUS_ACTIVE_COUNT] = HandleMsgMhfGetGuildWeeklyBonusActiveCount
handlerTable[network.MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER] = handleMsgMhfAddGuildWeeklyBonusExceptionalUser handlerTable[network.MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER] = HandleMsgMhfAddGuildWeeklyBonusExceptionalUser
handlerTable[network.MSG_MHF_GET_TOWER_INFO] = handleMsgMhfGetTowerInfo handlerTable[network.MSG_MHF_GET_TOWER_INFO] = handleMsgMhfGetTowerInfo
handlerTable[network.MSG_MHF_POST_TOWER_INFO] = handleMsgMhfPostTowerInfo handlerTable[network.MSG_MHF_POST_TOWER_INFO] = handleMsgMhfPostTowerInfo
handlerTable[network.MSG_MHF_GET_GEM_INFO] = handleMsgMhfGetGemInfo handlerTable[network.MSG_MHF_GET_GEM_INFO] = handleMsgMhfGetGemInfo
@@ -328,7 +328,7 @@ func init() {
handlerTable[network.MSG_MHF_GET_TINY_BIN] = handleMsgMhfGetTinyBin handlerTable[network.MSG_MHF_GET_TINY_BIN] = handleMsgMhfGetTinyBin
handlerTable[network.MSG_MHF_POST_TINY_BIN] = handleMsgMhfPostTinyBin handlerTable[network.MSG_MHF_POST_TINY_BIN] = handleMsgMhfPostTinyBin
handlerTable[network.MSG_MHF_GET_SENYU_DAILY_COUNT] = handleMsgMhfGetSenyuDailyCount handlerTable[network.MSG_MHF_GET_SENYU_DAILY_COUNT] = handleMsgMhfGetSenyuDailyCount
handlerTable[network.MSG_MHF_GET_GUILD_TARGET_MEMBER_NUM] = handleMsgMhfGetGuildTargetMemberNum handlerTable[network.MSG_MHF_GET_GUILD_TARGET_MEMBER_NUM] = HandleMsgMhfGetGuildTargetMemberNum
handlerTable[network.MSG_MHF_GET_BOOST_RIGHT] = handleMsgMhfGetBoostRight handlerTable[network.MSG_MHF_GET_BOOST_RIGHT] = handleMsgMhfGetBoostRight
handlerTable[network.MSG_MHF_START_BOOST_TIME] = handleMsgMhfStartBoostTime handlerTable[network.MSG_MHF_START_BOOST_TIME] = handleMsgMhfStartBoostTime
handlerTable[network.MSG_MHF_POST_BOOST_TIME_QUEST_RETURN] = handleMsgMhfPostBoostTimeQuestReturn handlerTable[network.MSG_MHF_POST_BOOST_TIME_QUEST_RETURN] = handleMsgMhfPostBoostTimeQuestReturn
@@ -341,19 +341,19 @@ func init() {
handlerTable[network.MSG_MHF_POST_RYOUDAMA] = handleMsgMhfPostRyoudama handlerTable[network.MSG_MHF_POST_RYOUDAMA] = handleMsgMhfPostRyoudama
handlerTable[network.MSG_MHF_GET_TENROUIRAI] = handleMsgMhfGetTenrouirai handlerTable[network.MSG_MHF_GET_TENROUIRAI] = handleMsgMhfGetTenrouirai
handlerTable[network.MSG_MHF_POST_TENROUIRAI] = handleMsgMhfPostTenrouirai handlerTable[network.MSG_MHF_POST_TENROUIRAI] = handleMsgMhfPostTenrouirai
handlerTable[network.MSG_MHF_POST_GUILD_SCOUT] = handleMsgMhfPostGuildScout handlerTable[network.MSG_MHF_POST_GUILD_SCOUT] = HandleMsgMhfPostGuildScout
handlerTable[network.MSG_MHF_CANCEL_GUILD_SCOUT] = handleMsgMhfCancelGuildScout handlerTable[network.MSG_MHF_CANCEL_GUILD_SCOUT] = HandleMsgMhfCancelGuildScout
handlerTable[network.MSG_MHF_ANSWER_GUILD_SCOUT] = handleMsgMhfAnswerGuildScout handlerTable[network.MSG_MHF_ANSWER_GUILD_SCOUT] = HandleMsgMhfAnswerGuildScout
handlerTable[network.MSG_MHF_GET_GUILD_SCOUT_LIST] = handleMsgMhfGetGuildScoutList handlerTable[network.MSG_MHF_GET_GUILD_SCOUT_LIST] = HandleMsgMhfGetGuildScoutList
handlerTable[network.MSG_MHF_GET_GUILD_MANAGE_RIGHT] = handleMsgMhfGetGuildManageRight handlerTable[network.MSG_MHF_GET_GUILD_MANAGE_RIGHT] = HandleMsgMhfGetGuildManageRight
handlerTable[network.MSG_MHF_SET_GUILD_MANAGE_RIGHT] = handleMsgMhfSetGuildManageRight handlerTable[network.MSG_MHF_SET_GUILD_MANAGE_RIGHT] = HandleMsgMhfSetGuildManageRight
handlerTable[network.MSG_MHF_PLAY_NORMAL_GACHA] = handleMsgMhfPlayNormalGacha handlerTable[network.MSG_MHF_PLAY_NORMAL_GACHA] = handleMsgMhfPlayNormalGacha
handlerTable[network.MSG_MHF_GET_DAILY_MISSION_MASTER] = handleMsgMhfGetDailyMissionMaster handlerTable[network.MSG_MHF_GET_DAILY_MISSION_MASTER] = handleMsgMhfGetDailyMissionMaster
handlerTable[network.MSG_MHF_GET_DAILY_MISSION_PERSONAL] = handleMsgMhfGetDailyMissionPersonal handlerTable[network.MSG_MHF_GET_DAILY_MISSION_PERSONAL] = handleMsgMhfGetDailyMissionPersonal
handlerTable[network.MSG_MHF_SET_DAILY_MISSION_PERSONAL] = handleMsgMhfSetDailyMissionPersonal handlerTable[network.MSG_MHF_SET_DAILY_MISSION_PERSONAL] = handleMsgMhfSetDailyMissionPersonal
handlerTable[network.MSG_MHF_GET_GACHA_PLAY_HISTORY] = handleMsgMhfGetGachaPlayHistory handlerTable[network.MSG_MHF_GET_GACHA_PLAY_HISTORY] = handleMsgMhfGetGachaPlayHistory
handlerTable[network.MSG_MHF_GET_REJECT_GUILD_SCOUT] = handleMsgMhfGetRejectGuildScout handlerTable[network.MSG_MHF_GET_REJECT_GUILD_SCOUT] = HandleMsgMhfGetRejectGuildScout
handlerTable[network.MSG_MHF_SET_REJECT_GUILD_SCOUT] = handleMsgMhfSetRejectGuildScout handlerTable[network.MSG_MHF_SET_REJECT_GUILD_SCOUT] = HandleMsgMhfSetRejectGuildScout
handlerTable[network.MSG_MHF_GET_CA_ACHIEVEMENT_HIST] = handleMsgMhfGetCaAchievementHist handlerTable[network.MSG_MHF_GET_CA_ACHIEVEMENT_HIST] = handleMsgMhfGetCaAchievementHist
handlerTable[network.MSG_MHF_SET_CA_ACHIEVEMENT_HIST] = handleMsgMhfSetCaAchievementHist handlerTable[network.MSG_MHF_SET_CA_ACHIEVEMENT_HIST] = handleMsgMhfSetCaAchievementHist
handlerTable[network.MSG_MHF_GET_KEEP_LOGIN_BOOST_STATUS] = handleMsgMhfGetKeepLoginBoostStatus handlerTable[network.MSG_MHF_GET_KEEP_LOGIN_BOOST_STATUS] = handleMsgMhfGetKeepLoginBoostStatus
@@ -378,8 +378,8 @@ func init() {
handlerTable[network.MSG_MHF_GET_UD_RANKING] = handleMsgMhfGetUdRanking handlerTable[network.MSG_MHF_GET_UD_RANKING] = handleMsgMhfGetUdRanking
handlerTable[network.MSG_MHF_GET_UD_MY_RANKING] = handleMsgMhfGetUdMyRanking handlerTable[network.MSG_MHF_GET_UD_MY_RANKING] = handleMsgMhfGetUdMyRanking
handlerTable[network.MSG_MHF_ACQUIRE_MONTHLY_REWARD] = handleMsgMhfAcquireMonthlyReward handlerTable[network.MSG_MHF_ACQUIRE_MONTHLY_REWARD] = handleMsgMhfAcquireMonthlyReward
handlerTable[network.MSG_MHF_GET_UD_GUILD_MAP_INFO] = handleMsgMhfGetUdGuildMapInfo handlerTable[network.MSG_MHF_GET_UD_GUILD_MAP_INFO] = HandleMsgMhfGetUdGuildMapInfo
handlerTable[network.MSG_MHF_GENERATE_UD_GUILD_MAP] = handleMsgMhfGenerateUdGuildMap handlerTable[network.MSG_MHF_GENERATE_UD_GUILD_MAP] = HandleMsgMhfGenerateUdGuildMap
handlerTable[network.MSG_MHF_GET_UD_TACTICS_POINT] = handleMsgMhfGetUdTacticsPoint handlerTable[network.MSG_MHF_GET_UD_TACTICS_POINT] = handleMsgMhfGetUdTacticsPoint
handlerTable[network.MSG_MHF_ADD_UD_TACTICS_POINT] = handleMsgMhfAddUdTacticsPoint handlerTable[network.MSG_MHF_ADD_UD_TACTICS_POINT] = handleMsgMhfAddUdTacticsPoint
handlerTable[network.MSG_MHF_GET_UD_TACTICS_RANKING] = handleMsgMhfGetUdTacticsRanking handlerTable[network.MSG_MHF_GET_UD_TACTICS_RANKING] = handleMsgMhfGetUdTacticsRanking
@@ -396,7 +396,7 @@ func init() {
handlerTable[network.MSG_MHF_SEX_CHANGER] = handleMsgMhfSexChanger handlerTable[network.MSG_MHF_SEX_CHANGER] = handleMsgMhfSexChanger
handlerTable[network.MSG_MHF_GET_LOBBY_CROWD] = handleMsgMhfGetLobbyCrowd handlerTable[network.MSG_MHF_GET_LOBBY_CROWD] = handleMsgMhfGetLobbyCrowd
handlerTable[network.MSG_SYS_reserve180] = handleMsgSysReserve180 handlerTable[network.MSG_SYS_reserve180] = handleMsgSysReserve180
handlerTable[network.MSG_MHF_GUILD_HUNTDATA] = handleMsgMhfGuildHuntdata handlerTable[network.MSG_MHF_GUILD_HUNTDATA] = HandleMsgMhfGuildHuntdata
handlerTable[network.MSG_MHF_ADD_KOURYOU_POINT] = handleMsgMhfAddKouryouPoint handlerTable[network.MSG_MHF_ADD_KOURYOU_POINT] = handleMsgMhfAddKouryouPoint
handlerTable[network.MSG_MHF_GET_KOURYOU_POINT] = handleMsgMhfGetKouryouPoint handlerTable[network.MSG_MHF_GET_KOURYOU_POINT] = handleMsgMhfGetKouryouPoint
handlerTable[network.MSG_MHF_EXCHANGE_KOURYOU_POINT] = handleMsgMhfExchangeKouryouPoint handlerTable[network.MSG_MHF_EXCHANGE_KOURYOU_POINT] = handleMsgMhfExchangeKouryouPoint
@@ -427,12 +427,12 @@ func init() {
handlerTable[network.MSG_MHF_LOAD_MEZFES_DATA] = handleMsgMhfLoadMezfesData handlerTable[network.MSG_MHF_LOAD_MEZFES_DATA] = handleMsgMhfLoadMezfesData
handlerTable[network.MSG_SYS_reserve19E] = handleMsgSysReserve19E handlerTable[network.MSG_SYS_reserve19E] = handleMsgSysReserve19E
handlerTable[network.MSG_SYS_reserve19F] = handleMsgSysReserve19F handlerTable[network.MSG_SYS_reserve19F] = handleMsgSysReserve19F
handlerTable[network.MSG_MHF_UPDATE_FORCE_GUILD_RANK] = handleMsgMhfUpdateForceGuildRank handlerTable[network.MSG_MHF_UPDATE_FORCE_GUILD_RANK] = HandleMsgMhfUpdateForceGuildRank
handlerTable[network.MSG_MHF_RESET_TITLE] = handleMsgMhfResetTitle handlerTable[network.MSG_MHF_RESET_TITLE] = handleMsgMhfResetTitle
handlerTable[network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD] = handleMsgMhfEnumerateGuildMessageBoard handlerTable[network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD] = HandleMsgMhfEnumerateGuildMessageBoard
handlerTable[network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD] = handleMsgMhfUpdateGuildMessageBoard handlerTable[network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD] = HandleMsgMhfUpdateGuildMessageBoard
handlerTable[network.MSG_SYS_reserve1A4] = handleMsgSysReserve1A4 handlerTable[network.MSG_SYS_reserve1A4] = handleMsgSysReserve1A4
handlerTable[network.MSG_MHF_REGIST_GUILD_ADVENTURE_DIVA] = handleMsgMhfRegistGuildAdventureDiva handlerTable[network.MSG_MHF_REGIST_GUILD_ADVENTURE_DIVA] = HandleMsgMhfRegistGuildAdventureDiva
handlerTable[network.MSG_SYS_reserve1A6] = handleMsgSysReserve1A6 handlerTable[network.MSG_SYS_reserve1A6] = handleMsgSysReserve1A6
handlerTable[network.MSG_SYS_reserve1A7] = handleMsgSysReserve1A7 handlerTable[network.MSG_SYS_reserve1A7] = handleMsgSysReserve1A7
handlerTable[network.MSG_SYS_reserve1A8] = handleMsgSysReserve1A8 handlerTable[network.MSG_SYS_reserve1A8] = handleMsgSysReserve1A8

View File

@@ -1,5 +1,9 @@
package channelserver package channelserver
import (
"erupe-ce/config"
)
type i18n struct { type i18n struct {
language string language string
cafe struct { cafe struct {
@@ -101,9 +105,9 @@ type i18n struct {
} }
} }
func getLangStrings(server *Server) i18n { func getLangStrings(server *ChannelServer) i18n {
var i i18n var i i18n
switch server.erupeConfig.Language { switch config.GetConfig().Language {
case "jp": case "jp":
i.language = "日本語" i.language = "日本語"
i.cafe.reset = "%d/%dにリセット" i.cafe.reset = "%d/%dにリセット"

View File

@@ -13,7 +13,7 @@ type Raviente struct {
support []uint32 support []uint32
} }
func (server *Server) resetRaviente() { func (server *ChannelServer) resetRaviente() {
for _, semaphore := range server.semaphore { for _, semaphore := range server.semaphore {
if strings.HasPrefix(semaphore.name, "hs_l0") { if strings.HasPrefix(semaphore.name, "hs_l0") {
return return
@@ -26,7 +26,7 @@ func (server *Server) resetRaviente() {
server.raviente.support = make([]uint32, 30) server.raviente.support = make([]uint32, 30)
} }
func (server *Server) GetRaviMultiplier() float64 { func (server *ChannelServer) GetRaviMultiplier() float64 {
raviSema := server.getRaviSemaphore() raviSema := server.getRaviSemaphore()
if raviSema != nil { if raviSema != nil {
var minPlayers int var minPlayers int
@@ -43,7 +43,7 @@ func (server *Server) GetRaviMultiplier() float64 {
return 0 return 0
} }
func (server *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update bool) (uint32, uint32) { func (server *ChannelServer) UpdateRavi(semaID uint32, index uint8, value uint32, update bool) (uint32, uint32) {
var prev uint32 var prev uint32
var dest *[]uint32 var dest *[]uint32
switch semaID { switch semaID {

View File

@@ -3,29 +3,29 @@ package channelserver
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network"
"erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/logger"
"erupe-ce/utils/mhfcourse" "erupe-ce/utils/mhfcourse"
"erupe-ce/utils/stringstack"
"fmt" "fmt"
"io" "io"
"net" "net"
"sync" "sync"
"time" "time"
"erupe-ce/network"
"erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe"
"erupe-ce/utils/logger"
"erupe-ce/utils/stringstack"
"go.uber.org/zap" "go.uber.org/zap"
) )
// Session holds state for the channel server connection. // Session holds state for the channel server connection.
type Session struct { type Session struct {
sync.Mutex sync.Mutex
logger logger.Logger Logger logger.Logger
server *Server Server *ChannelServer
rawConn net.Conn rawConn net.Conn
cryptConn *network.CryptConn cryptConn *network.CryptConn
sendPackets chan mhfpacket.MHFPacket sendPackets chan mhfpacket.MHFPacket
@@ -37,7 +37,7 @@ type Session struct {
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
stagePass string // Temporary storage stagePass string // Temporary storage
prevGuildID uint32 // Stores the last GuildID used in InfoGuild prevGuildID uint32 // Stores the last GuildID used in InfoGuild
charID uint32 CharID uint32
logKey []byte logKey []byte
sessionStart int64 sessionStart int64
courses []mhfcourse.Course courses []mhfcourse.Course
@@ -66,10 +66,10 @@ type Session struct {
} }
// NewSession creates a new Session type. // NewSession creates a new Session type.
func NewSession(server *Server, conn net.Conn) *Session { func NewSession(server *ChannelServer, conn net.Conn) *Session {
s := &Session{ s := &Session{
logger: server.logger.Named(conn.RemoteAddr().String()), Logger: server.logger.Named(conn.RemoteAddr().String()),
server: server, Server: server,
rawConn: conn, rawConn: conn,
cryptConn: network.NewCryptConn(conn), cryptConn: network.NewCryptConn(conn),
sendPackets: make(chan mhfpacket.MHFPacket, 20), sendPackets: make(chan mhfpacket.MHFPacket, 20),
@@ -85,7 +85,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
// Start starts the session packet send and recv loop(s). // Start starts the session packet send and recv loop(s).
func (s *Session) Start() { func (s *Session) Start() {
s.logger.Debug("New connection", zap.String("RemoteAddr", s.rawConn.RemoteAddr().String())) s.Logger.Debug("New connection", zap.String("RemoteAddr", s.rawConn.RemoteAddr().String()))
// Unlike the sign and entrance server, // Unlike the sign and entrance server,
// the client DOES NOT initalize the channel connection with 8 NULL bytes. // the client DOES NOT initalize the channel connection with 8 NULL bytes.
go s.sendLoop() go s.sendLoop()
@@ -97,7 +97,7 @@ func (s *Session) QueueSendMHF(pkt mhfpacket.MHFPacket) {
select { select {
case s.sendPackets <- pkt: case s.sendPackets <- pkt:
default: default:
s.logger.Warn("Packet queue too full, dropping!") s.Logger.Warn("Packet queue too full, dropping!")
} }
} }
@@ -123,11 +123,11 @@ func (s *Session) sendLoop() {
if len(buffer) > 0 { if len(buffer) > 0 {
err := s.cryptConn.SendPacket(buffer) err := s.cryptConn.SendPacket(buffer)
if err != nil { if err != nil {
s.logger.Warn("Failed to send packet") s.Logger.Warn("Failed to send packet")
} }
buffer = buffer[:0] buffer = buffer[:0]
} }
time.Sleep(time.Duration(_config.ErupeConfig.LoopDelay) * time.Millisecond) time.Sleep(time.Duration(config.GetConfig().LoopDelay) * time.Millisecond)
} }
} }
@@ -143,16 +143,16 @@ func (s *Session) recvLoop() {
} }
pkt, err := s.cryptConn.ReadPacket() pkt, err := s.cryptConn.ReadPacket()
if err == io.EOF { if err == io.EOF {
s.logger.Info(fmt.Sprintf("[%s] Disconnected", s.Name)) s.Logger.Info(fmt.Sprintf("[%s] Disconnected", s.Name))
logoutPlayer(s) logoutPlayer(s)
return return
} else if err != nil { } else if err != nil {
s.logger.Warn("Error on ReadPacket, exiting recv loop", zap.Error(err)) s.Logger.Warn("Error on ReadPacket, exiting recv loop", zap.Error(err))
logoutPlayer(s) logoutPlayer(s)
return return
} }
s.handlePacketGroup(pkt) s.handlePacketGroup(pkt)
time.Sleep(time.Duration(_config.ErupeConfig.LoopDelay) * time.Millisecond) time.Sleep(time.Duration(config.GetConfig().LoopDelay) * time.Millisecond)
} }
} }
@@ -220,9 +220,9 @@ func ignored(opcode network.PacketID) bool {
} }
func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipient string) { func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipient string) {
if sender == "Server" && !s.server.erupeConfig.DebugOptions.LogOutboundMessages { if sender == "Server" && !config.GetConfig().DebugOptions.LogOutboundMessages {
return return
} else if sender != "Server" && !s.server.erupeConfig.DebugOptions.LogInboundMessages { } else if sender != "Server" && !config.GetConfig().DebugOptions.LogInboundMessages {
return return
} }
@@ -240,8 +240,8 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
fmt.Printf("[%s] -> [%s]\n", sender, recipient) fmt.Printf("[%s] -> [%s]\n", sender, recipient)
} }
fmt.Printf("Opcode: (Dec: %d Hex: 0x%04X Name: %s) \n", opcode, opcode, opcodePID) fmt.Printf("Opcode: (Dec: %d Hex: 0x%04X Name: %s) \n", opcode, opcode, opcodePID)
if s.server.erupeConfig.DebugOptions.LogMessageData { if config.GetConfig().DebugOptions.LogMessageData {
if len(data) <= s.server.erupeConfig.DebugOptions.MaxHexdumpLength { if len(data) <= config.GetConfig().DebugOptions.MaxHexdumpLength {
fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data))
} else { } else {
fmt.Printf("Data [%d bytes]: (Too long!)\n\n", len(data)) fmt.Printf("Data [%d bytes]: (Too long!)\n\n", len(data))
@@ -254,23 +254,23 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
func (s *Session) SetObjectID() { func (s *Session) SetObjectID() {
for i := uint16(1); i < 127; i++ { for i := uint16(1); i < 127; i++ {
exists := false exists := false
for _, j := range s.server.objectIDs { for _, j := range s.Server.objectIDs {
if i == j { if i == j {
exists = true exists = true
break break
} }
} }
if !exists { if !exists {
s.server.objectIDs[s] = i s.Server.objectIDs[s] = i
return return
} }
} }
s.server.objectIDs[s] = 0 s.Server.objectIDs[s] = 0
} }
func (s *Session) NextObjectID() uint32 { func (s *Session) NextObjectID() uint32 {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(s.server.objectIDs[s]) bf.WriteUint16(s.Server.objectIDs[s])
s.objectIndex++ s.objectIndex++
bf.WriteUint16(s.objectIndex) bf.WriteUint16(s.objectIndex)
bf.Seek(0, 0) bf.Seek(0, 0)
@@ -287,7 +287,11 @@ func (s *Session) GetSemaphoreID() uint32 {
func (s *Session) isOp() bool { func (s *Session) isOp() bool {
var op bool var op bool
err := s.server.db.QueryRow(`SELECT op FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&op) database, err := db.GetDB()
if err != nil {
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow(`SELECT op FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&op)
if err == nil && op { if err == nil && op {
return true return true
} }

View File

@@ -1,7 +1,7 @@
package discordbot package discordbot
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"regexp" "regexp"
@@ -38,18 +38,14 @@ var Commands = []*discordgo.ApplicationCommand{
type DiscordBot struct { type DiscordBot struct {
Session *discordgo.Session Session *discordgo.Session
config *_config.Config config *config.Config
logger logger.Logger logger logger.Logger
MainGuild *discordgo.Guild MainGuild *discordgo.Guild
RelayChannel *discordgo.Channel RelayChannel *discordgo.Channel
} }
type Options struct { func NewDiscordBot() (discordBot *DiscordBot, err error) {
Config *_config.Config session, err := discordgo.New("Bot " + config.GetConfig().Discord.BotToken)
}
func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) {
session, err := discordgo.New("Bot " + options.Config.Discord.BotToken)
discordLogger := logger.Get().Named("discord") discordLogger := logger.Get().Named("discord")
if err != nil { if err != nil {
discordLogger.Fatal("Discord failed", zap.Error(err)) discordLogger.Fatal("Discord failed", zap.Error(err))
@@ -58,8 +54,8 @@ func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) {
var relayChannel *discordgo.Channel var relayChannel *discordgo.Channel
if options.Config.Discord.RelayChannel.Enabled { if config.GetConfig().Discord.RelayChannel.Enabled {
relayChannel, err = session.Channel(options.Config.Discord.RelayChannel.RelayChannelID) relayChannel, err = session.Channel(config.GetConfig().Discord.RelayChannel.RelayChannelID)
} }
if err != nil { if err != nil {
@@ -68,7 +64,7 @@ func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) {
} }
discordBot = &DiscordBot{ discordBot = &DiscordBot{
config: options.Config, config: config.GetConfig(),
logger: discordLogger, logger: discordLogger,
Session: session, Session: session,
RelayChannel: relayChannel, RelayChannel: relayChannel,

View File

@@ -1,4 +1,4 @@
package entranceserver package entrance
import ( import (
"encoding/hex" "encoding/hex"
@@ -8,45 +8,33 @@ import (
"strings" "strings"
"sync" "sync"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
) )
// Server is a MHF entrance server. // EntranceServer is a MHF entrance server.
type Server struct { type EntranceServer struct {
sync.Mutex sync.Mutex
logger logger.Logger logger logger.Logger
erupeConfig *_config.Config
db *sqlx.DB
listener net.Listener listener net.Listener
isShuttingDown bool isShuttingDown bool
} }
// Config struct allows configuring the server.
type Config struct {
Logger logger.Logger
DB *sqlx.DB
ErupeConfig *_config.Config
}
// NewServer creates a new Server type. // NewServer creates a new Server type.
func NewServer(config *Config) *Server { func NewServer() *EntranceServer {
server := &Server{ server := &EntranceServer{
logger: config.Logger, logger: logger.Get().Named("entrance"),
erupeConfig: config.ErupeConfig,
db: config.DB,
} }
return server return server
} }
// Start starts the server in a new goroutine. // Start starts the server in a new goroutine.
func (server *Server) Start() error { func (server *EntranceServer) Start() error {
l, err := net.Listen("tcp", fmt.Sprintf(":%d", server.erupeConfig.Entrance.Port)) l, err := net.Listen("tcp", fmt.Sprintf(":%d", config.GetConfig().Entrance.Port))
if err != nil { if err != nil {
return err return err
} }
@@ -59,7 +47,7 @@ func (server *Server) Start() error {
} }
// Shutdown exits the server gracefully. // Shutdown exits the server gracefully.
func (server *Server) Shutdown() { func (server *EntranceServer) Shutdown() {
server.logger.Debug("Shutting down...") server.logger.Debug("Shutting down...")
server.Lock() server.Lock()
@@ -71,7 +59,7 @@ func (server *Server) Shutdown() {
} }
// acceptClients handles accepting new clients in a loop. // acceptClients handles accepting new clients in a loop.
func (server *Server) acceptClients() { func (server *EntranceServer) acceptClients() {
for { for {
conn, err := server.listener.Accept() conn, err := server.listener.Accept()
if err != nil { if err != nil {
@@ -92,7 +80,7 @@ func (server *Server) acceptClients() {
} }
} }
func (server *Server) handleEntranceServerConnection(conn net.Conn) { func (server *EntranceServer) handleEntranceServerConnection(conn net.Conn) {
defer conn.Close() defer conn.Close()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes. // Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8) nullInit := make([]byte, 8)
@@ -113,7 +101,7 @@ func (server *Server) handleEntranceServerConnection(conn net.Conn) {
return return
} }
if server.erupeConfig.DebugOptions.LogInboundMessages { if config.GetConfig().DebugOptions.LogInboundMessages {
fmt.Printf("[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt)) fmt.Printf("[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt))
} }
@@ -121,7 +109,7 @@ func (server *Server) handleEntranceServerConnection(conn net.Conn) {
if strings.Split(conn.RemoteAddr().String(), ":")[0] == "127.0.0.1" { if strings.Split(conn.RemoteAddr().String(), ":")[0] == "127.0.0.1" {
local = true local = true
} }
data := makeSv2Resp(server.erupeConfig, server, local) data := makeSv2Resp(server, local)
if len(pkt) > 5 { if len(pkt) > 5 {
data = append(data, makeUsrResp(pkt, server)...) data = append(data, makeUsrResp(pkt, server)...)
} }

View File

@@ -1,39 +1,41 @@
package entranceserver package entrance
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network/crypto/bin8" "erupe-ce/network/crypto/bin8"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt" "fmt"
"net" "net"
) )
func encodeServerInfo(config *_config.Config, server *Server, local bool) []byte { func encodeServerInfo(server *EntranceServer, local bool) []byte {
serverInfos := config.Entrance.Entries serverInfos := config.GetConfig().Entrance.Entries
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
for serverIdx, si := range serverInfos { for serverIdx, si := range serverInfos {
// Prevent MezFes Worlds displaying on Z1 // Prevent MezFes Worlds displaying on Z1
if config.ClientID <= _config.Z1 { if config.GetConfig().ClientID <= config.Z1 {
if si.Type == 6 { if si.Type == 6 {
continue continue
} }
} }
if config.ClientID <= _config.G6 { if config.GetConfig().ClientID <= config.G6 {
if si.Type == 5 { if si.Type == 5 {
continue continue
} }
} }
if si.IP == "" { if si.IP == "" {
si.IP = config.Host si.IP = config.GetConfig().Host
} }
if local { if local {
bf.WriteUint32(0x0100007F) // 127.0.0.1 bf.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP("127.0.0.1").To4()))
} else { } else {
bf.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(si.IP).To4())) bf.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(si.IP).To4()))
} }
@@ -42,36 +44,40 @@ func encodeServerInfo(config *_config.Config, server *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(uint8(((gametime.TimeAdjusted().Unix() / 86400) + int64(serverIdx)) % 3)) bf.WriteUint8(uint8(((gametime.TimeAdjusted().Unix() / 86400) + int64(serverIdx)) % 3))
if server.erupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
bf.WriteUint8(si.Recommended) bf.WriteUint8(si.Recommended)
} }
fullName := append(append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...), stringsupport.UTF8ToSJIS(si.Description)...) fullName := append(append(stringsupport.UTF8ToSJIS(si.Name), []byte{0x00}...), stringsupport.UTF8ToSJIS(si.Description)...)
if server.erupeConfig.ClientID >= _config.G1 && server.erupeConfig.ClientID <= _config.G5 { if config.GetConfig().ClientID >= config.G1 && config.GetConfig().ClientID <= config.G5 {
bf.WriteUint8(uint8(len(fullName))) bf.WriteUint8(uint8(len(fullName)))
bf.WriteBytes(fullName) bf.WriteBytes(fullName)
} else { } else {
if server.erupeConfig.ClientID >= _config.G51 { if config.GetConfig().ClientID >= config.G51 {
bf.WriteUint8(0) // Ignored bf.WriteUint8(0) // Ignored
} }
bf.WriteBytes(stringsupport.PaddedString(string(fullName), 65, false)) bf.WriteBytes(stringsupport.PaddedString(string(fullName), 65, false))
} }
if server.erupeConfig.ClientID >= _config.GG { if config.GetConfig().ClientID >= config.GG {
bf.WriteUint32(si.AllowedClientFlags) bf.WriteUint32(si.AllowedClientFlags)
} }
for channelIdx, ci := range si.Channels { for channelIdx, ci := range si.Channels {
sid := (serverIdx<<8 | 4096) + (channelIdx | 16) sid := (serverIdx<<8 | 4096) + (channelIdx | 16)
if _config.ErupeConfig.DebugOptions.ProxyPort != 0 { if config.GetConfig().DebugOptions.ProxyPort != 0 {
bf.WriteUint16(_config.ErupeConfig.DebugOptions.ProxyPort) bf.WriteUint16(config.GetConfig().DebugOptions.ProxyPort)
} else { } else {
bf.WriteUint16(ci.Port) bf.WriteUint16(ci.Port)
} }
bf.WriteUint16(uint16(channelIdx | 16)) bf.WriteUint16(uint16(channelIdx | 16))
bf.WriteUint16(ci.MaxPlayers) bf.WriteUint16(ci.MaxPlayers)
var currentPlayers uint16 var currentPlayers uint16
server.db.QueryRow("SELECT current_players FROM servers WHERE server_id=$1", sid).Scan(&currentPlayers) database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
database.QueryRow("SELECT current_players FROM servers WHERE server_id=$1", sid).Scan(&currentPlayers)
bf.WriteUint16(currentPlayers) bf.WriteUint16(currentPlayers)
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint16(0) bf.WriteUint16(0)
@@ -86,7 +92,7 @@ func encodeServerInfo(config *_config.Config, server *Server, local bool) []byte
} }
} }
bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix()))
bf.WriteUint32(uint32(server.erupeConfig.GameplayOptions.ClanMemberLimits[len(server.erupeConfig.GameplayOptions.ClanMemberLimits)-1][1])) bf.WriteUint32(uint32(config.GetConfig().GameplayOptions.ClanMemberLimits[len(config.GetConfig().GameplayOptions.ClanMemberLimits)-1][1]))
return bf.Data() return bf.Data()
} }
@@ -108,11 +114,11 @@ func makeHeader(data []byte, respType string, entryCount uint16, key byte) []byt
return bf.Data() return bf.Data()
} }
func makeSv2Resp(config *_config.Config, server *Server, local bool) []byte { func makeSv2Resp(server *EntranceServer, local bool) []byte {
serverInfos := config.Entrance.Entries serverInfos := config.GetConfig().Entrance.Entries
// Decrease by the number of MezFes Worlds // Decrease by the number of MezFes Worlds
var mf int var mf int
if config.ClientID <= _config.Z1 { if config.GetConfig().ClientID <= config.Z1 {
for _, si := range serverInfos { for _, si := range serverInfos {
if si.Type == 6 { if si.Type == 6 {
mf++ mf++
@@ -121,21 +127,21 @@ func makeSv2Resp(config *_config.Config, server *Server, local bool) []byte {
} }
// and Return Worlds // and Return Worlds
var ret int var ret int
if config.ClientID <= _config.G6 { if config.GetConfig().ClientID <= config.G6 {
for _, si := range serverInfos { for _, si := range serverInfos {
if si.Type == 5 { if si.Type == 5 {
ret++ ret++
} }
} }
} }
rawServerData := encodeServerInfo(config, server, local) rawServerData := encodeServerInfo(server, local)
if server.erupeConfig.DebugOptions.LogOutboundMessages { if config.GetConfig().DebugOptions.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" respType := "SV2"
if config.ClientID <= _config.G32 { if config.GetConfig().ClientID <= config.G32 {
respType = "SVR" respType = "SVR"
} }
@@ -144,16 +150,20 @@ func makeSv2Resp(config *_config.Config, server *Server, local bool) []byte {
return bf.Data() return bf.Data()
} }
func makeUsrResp(pkt []byte, server *Server) []byte { func makeUsrResp(pkt []byte, server *EntranceServer) []byte {
bf := byteframe.NewByteFrameFromBytes(pkt) bf := byteframe.NewByteFrameFromBytes(pkt)
_ = bf.ReadUint32() // ALL+ _ = bf.ReadUint32() // ALL+
_ = bf.ReadUint8() // 0x00 _ = bf.ReadUint8() // 0x00
userEntries := bf.ReadUint16() userEntries := bf.ReadUint16()
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
database, err := db.GetDB()
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
for i := 0; i < int(userEntries); i++ { for i := 0; i < int(userEntries); i++ {
cid := bf.ReadUint32() cid := bf.ReadUint32()
var sid uint16 var sid uint16
err := server.db.QueryRow("SELECT(SELECT server_id FROM sign_sessions WHERE char_id=$1) AS _", cid).Scan(&sid) err := database.QueryRow("SELECT(SELECT server_id FROM sign_sessions WHERE char_id=$1) AS _", cid).Scan(&sid)
if err != nil { if err != nil {
resp.WriteUint16(0) resp.WriteUint16(0)
} else { } else {
@@ -162,7 +172,7 @@ func makeUsrResp(pkt []byte, server *Server) []byte {
resp.WriteUint16(0) resp.WriteUint16(0)
} }
if server.erupeConfig.DebugOptions.LogOutboundMessages { if config.GetConfig().DebugOptions.LogOutboundMessages {
fmt.Printf("[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(resp.Data()), hex.Dump(resp.Data())) fmt.Printf("[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(resp.Data()), hex.Dump(resp.Data()))
} }

318
server/sign/dbutils.go Normal file
View File

@@ -0,0 +1,318 @@
package sign
import (
"database/sql"
"errors"
"erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/mhfcourse"
"erupe-ce/utils/token"
"fmt"
"strings"
"time"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
)
func (server *SignServer) newUserChara(uid uint32) error {
var numNewChars int
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", uid).Scan(&numNewChars)
if err != nil {
return err
}
// prevent users with an uninitialised character from creating more
if numNewChars >= 1 {
return err
}
_, err = database.Exec(`
INSERT INTO characters (
user_id, is_female, is_new_character, name, unk_desc_string,
hr, gr, weapon_type, last_login)
VALUES($1, False, True, '', '', 0, 0, 0, $2)`,
uid,
uint32(time.Now().Unix()),
)
if err != nil {
return err
}
return nil
}
func (server *SignServer) registerDBAccount(username string, password string) (uint32, error) {
var uid uint32
server.logger.Info("Creating user", zap.String("User", username))
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
// Create salted hash of user password
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return 0, err
}
err = database.QueryRow("INSERT INTO users (username, password, return_expires) VALUES ($1, $2, $3) RETURNING id", username, string(passwordHash), time.Now().Add(time.Hour*24*30)).Scan(&uid)
if err != nil {
return 0, err
}
return uid, nil
}
type character struct {
ID uint32 `db:"id"`
IsFemale bool `db:"is_female"`
IsNewCharacter bool `db:"is_new_character"`
Name string `db:"name"`
UnkDescString string `db:"unk_desc_string"`
HR uint16 `db:"hr"`
GR uint16 `db:"gr"`
WeaponType uint16 `db:"weapon_type"`
LastLogin uint32 `db:"last_login"`
}
func (server *SignServer) getCharactersForUser(uid uint32) ([]character, error) {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
characters := make([]character, 0)
err = database.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hr, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false ORDER BY id", uid)
if err != nil {
return nil, err
}
return characters, nil
}
func (server *SignServer) getReturnExpiry(uid uint32) time.Time {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var returnExpiry, lastLogin time.Time
database.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid)
if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) {
returnExpiry = time.Now().Add(time.Hour * 24 * 30)
database.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
} else {
err := database.Get(&returnExpiry, "SELECT return_expires FROM users WHERE id=$1", uid)
if err != nil {
returnExpiry = time.Now()
database.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
}
}
database.Exec("UPDATE users SET last_login=$1 WHERE id=$2", time.Now(), uid)
return returnExpiry
}
func (server *SignServer) getLastCID(uid uint32) uint32 {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var lastPlayed uint32
_ = database.QueryRow("SELECT last_character FROM users WHERE id=$1", uid).Scan(&lastPlayed)
return lastPlayed
}
func (server *SignServer) getUserRights(uid uint32) uint32 {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var rights uint32
if uid != 0 {
_ = database.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights)
_, rights = mhfcourse.GetCourseStruct(rights)
}
return rights
}
type members struct {
CID uint32 // Local character ID
ID uint32 `db:"id"`
Name string `db:"name"`
}
func (server *SignServer) getFriendsForCharacters(chars []character) []members {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
friends := make([]members, 0)
for _, char := range chars {
friendsCSV := ""
err := database.QueryRow("SELECT friends FROM characters WHERE id=$1", char.ID).Scan(&friendsCSV)
friendsSlice := strings.Split(friendsCSV, ",")
friendQuery := "SELECT id, name FROM characters WHERE id="
for i := 0; i < len(friendsSlice); i++ {
friendQuery += friendsSlice[i]
if i+1 != len(friendsSlice) {
friendQuery += " OR id="
}
}
charFriends := make([]members, 0)
err = database.Select(&charFriends, friendQuery)
if err != nil {
continue
}
for i := range charFriends {
charFriends[i].CID = char.ID
}
friends = append(friends, charFriends...)
}
return friends
}
func (server *SignServer) getGuildmatesForCharacters(chars []character) []members {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
guildmates := make([]members, 0)
for _, char := range chars {
var inGuild int
_ = database.QueryRow("SELECT count(*) FROM guild_characters WHERE character_id=$1", char.ID).Scan(&inGuild)
if inGuild > 0 {
var guildID int
err := database.QueryRow("SELECT guild_id FROM guild_characters WHERE character_id=$1", char.ID).Scan(&guildID)
if err != nil {
continue
}
charGuildmates := make([]members, 0)
err = database.Select(&charGuildmates, "SELECT character_id AS id, c.name FROM guild_characters gc JOIN characters c ON c.id = gc.character_id WHERE guild_id=$1 AND character_id!=$2", guildID, char.ID)
if err != nil {
continue
}
for i := range charGuildmates {
charGuildmates[i].CID = char.ID
}
guildmates = append(guildmates, charGuildmates...)
}
}
return guildmates
}
func (server *SignServer) deleteCharacter(cid int, token string, tokenID uint32) error {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if !server.validateToken(token, tokenID) {
return errors.New("invalid token")
}
var isNew bool
err = database.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", cid).Scan(&isNew)
if isNew {
_, err = database.Exec("DELETE FROM characters WHERE id = $1", cid)
} else {
_, err = database.Exec("UPDATE characters SET deleted = true WHERE id = $1", cid)
}
if err != nil {
return err
}
return nil
}
// Unused
func (server *SignServer) checkToken(uid uint32) (bool, error) {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var exists int
err = database.QueryRow("SELECT count(*) FROM sign_sessions WHERE user_id = $1", uid).Scan(&exists)
if err != nil {
return false, err
}
if exists > 0 {
return true, nil
}
return false, nil
}
func (server *SignServer) registerUidToken(uid uint32) (uint32, string, error) {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
_token := token.Generate(16)
var tid uint32
err = database.QueryRow(`INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2) RETURNING id`, uid, _token).Scan(&tid)
return tid, _token, err
}
func (server *SignServer) registerPsnToken(psn string) (uint32, string, error) {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
_token := token.Generate(16)
var tid uint32
err = database.QueryRow(`INSERT INTO sign_sessions (psn_id, token) VALUES ($1, $2) RETURNING id`, psn, _token).Scan(&tid)
return tid, _token, err
}
func (server *SignServer) validateToken(token string, tokenID uint32) bool {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
query := `SELECT count(*) FROM sign_sessions WHERE token = $1`
if tokenID > 0 {
query += ` AND id = $2`
}
var exists int
err = database.QueryRow(query, token, tokenID).Scan(&exists)
if err != nil || exists == 0 {
return false
}
return true
}
func (server *SignServer) validateLogin(user string, pass string) (uint32, RespID) {
database, err := db.GetDB() // Capture both return values
if err != nil {
server.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
var uid uint32
var passDB string
err = database.QueryRow(`SELECT id, password FROM users WHERE username = $1`, user).Scan(&uid, &passDB)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
server.logger.Info("User not found", zap.String("User", user))
if config.GetConfig().AutoCreateAccount {
uid, err = server.registerDBAccount(user, pass)
if err == nil {
return uid, SIGN_SUCCESS
} else {
return 0, SIGN_EABORT
}
}
return 0, SIGN_EAUTH
}
return 0, SIGN_EABORT
} else {
if bcrypt.CompareHashAndPassword([]byte(passDB), []byte(pass)) == nil {
var bans int
err = database.QueryRow(`SELECT count(*) FROM bans WHERE user_id=$1 AND expires IS NULL`, uid).Scan(&bans)
if err == nil && bans > 0 {
return uid, SIGN_EELIMINATE
}
err = database.QueryRow(`SELECT count(*) FROM bans WHERE user_id=$1 AND expires > now()`, uid).Scan(&bans)
if err == nil && bans > 0 {
return uid, SIGN_ESUSPEND
}
return uid, SIGN_SUCCESS
}
return 0, SIGN_EPASS
}
}

View File

@@ -1,12 +1,13 @@
package signserver package sign
import ( import (
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/db"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
ps "erupe-ce/utils/pascalstring" ps "erupe-ce/utils/pascalstring"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
_config "erupe-ce/config" "erupe-ce/config"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@@ -40,7 +41,7 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
return bf.Data() return bf.Data()
} }
if s.client == PS3 && (s.server.erupeConfig.PatchServerFile == "" || s.server.erupeConfig.PatchServerManifest == "") { if s.client == PS3 && (config.GetConfig().PatchServerFile == "" || config.GetConfig().PatchServerManifest == "") {
bf.WriteUint8(uint8(SIGN_EABORT)) bf.WriteUint8(uint8(SIGN_EABORT))
return bf.Data() return bf.Data()
} }
@@ -53,16 +54,16 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
bf.WriteBytes([]byte(sessToken)) bf.WriteBytes([]byte(sessToken))
bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix())) bf.WriteUint32(uint32(gametime.TimeAdjusted().Unix()))
if s.client == PS3 { if s.client == PS3 {
ps.Uint8(bf, fmt.Sprintf("%s/ps3", s.server.erupeConfig.PatchServerManifest), false) ps.Uint8(bf, fmt.Sprintf("%s/ps3", config.GetConfig().PatchServerManifest), false)
ps.Uint8(bf, fmt.Sprintf("%s/ps3", s.server.erupeConfig.PatchServerFile), false) ps.Uint8(bf, fmt.Sprintf("%s/ps3", config.GetConfig().PatchServerFile), false)
} else { } else {
ps.Uint8(bf, s.server.erupeConfig.PatchServerManifest, false) ps.Uint8(bf, config.GetConfig().PatchServerManifest, false)
ps.Uint8(bf, s.server.erupeConfig.PatchServerFile, false) ps.Uint8(bf, config.GetConfig().PatchServerFile, false)
} }
if strings.Split(s.rawConn.RemoteAddr().String(), ":")[0] == "127.0.0.1" { if strings.Split(s.rawConn.RemoteAddr().String(), ":")[0] == "127.0.0.1" {
ps.Uint8(bf, fmt.Sprintf("127.0.0.1:%d", s.server.erupeConfig.Entrance.Port), false) ps.Uint8(bf, fmt.Sprintf("127.0.0.1:%d", config.GetConfig().Entrance.Port), false)
} else { } else {
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false) ps.Uint8(bf, fmt.Sprintf("%s:%d", config.GetConfig().Host, config.GetConfig().Entrance.Port), false)
} }
lastPlayed := uint32(0) lastPlayed := uint32(0)
@@ -71,7 +72,7 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
lastPlayed = char.ID lastPlayed = char.ID
} }
bf.WriteUint32(char.ID) bf.WriteUint32(char.ID)
if s.server.erupeConfig.DebugOptions.MaxLauncherHR { if config.GetConfig().DebugOptions.MaxLauncherHR {
bf.WriteUint16(999) bf.WriteUint16(999)
} else { } else {
bf.WriteUint16(char.HR) bf.WriteUint16(char.HR)
@@ -84,7 +85,7 @@ 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.ClientID >= _config.G7 { if config.GetConfig().ClientID >= config.G7 {
bf.WriteUint16(char.GR) bf.WriteUint16(char.GR)
bf.WriteUint8(0) // Unk bf.WriteUint8(0) // Unk
bf.WriteUint8(0) // Unk bf.WriteUint8(0) // Unk
@@ -125,13 +126,13 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
} }
} }
if s.server.erupeConfig.HideLoginNotice { if config.GetConfig().HideLoginNotice {
bf.WriteBool(false) bf.WriteBool(false)
} else { } else {
bf.WriteBool(true) bf.WriteBool(true)
bf.WriteUint8(0) bf.WriteUint8(0)
bf.WriteUint8(0) bf.WriteUint8(0)
ps.Uint16(bf, strings.Join(s.server.erupeConfig.LoginNotices[:], "<PAGE>"), true) ps.Uint16(bf, strings.Join(config.GetConfig().LoginNotices[:], "<PAGE>"), true)
} }
bf.WriteUint32(s.server.getLastCID(uid)) bf.WriteUint32(s.server.getLastCID(uid))
@@ -332,18 +333,21 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
bf.WriteUint16(uint16(len(filters.Data()))) bf.WriteUint16(uint16(len(filters.Data())))
bf.WriteBytes(filters.Data()) bf.WriteBytes(filters.Data())
database, err := db.GetDB() // Capture both return values
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if s.client == VITA || s.client == PS3 || s.client == PS4 { if s.client == VITA || s.client == PS3 || s.client == PS4 {
var psnUser string var psnUser string
s.server.db.QueryRow("SELECT psn_id FROM users WHERE id = $1", uid).Scan(&psnUser) database.QueryRow("SELECT psn_id FROM users WHERE id = $1", uid).Scan(&psnUser)
bf.WriteBytes(stringsupport.PaddedString(psnUser, 20, true)) bf.WriteBytes(stringsupport.PaddedString(psnUser, 20, true))
} }
bf.WriteUint16(s.server.erupeConfig.DebugOptions.CapLink.Values[0]) bf.WriteUint16(config.GetConfig().DebugOptions.CapLink.Values[0])
if s.server.erupeConfig.DebugOptions.CapLink.Values[0] == 51728 { if config.GetConfig().DebugOptions.CapLink.Values[0] == 51728 {
bf.WriteUint16(s.server.erupeConfig.DebugOptions.CapLink.Values[1]) bf.WriteUint16(config.GetConfig().DebugOptions.CapLink.Values[1])
if s.server.erupeConfig.DebugOptions.CapLink.Values[1] == 20000 || s.server.erupeConfig.DebugOptions.CapLink.Values[1] == 20002 { if config.GetConfig().DebugOptions.CapLink.Values[1] == 20000 || config.GetConfig().DebugOptions.CapLink.Values[1] == 20002 {
ps.Uint16(bf, s.server.erupeConfig.DebugOptions.CapLink.Key, false) ps.Uint16(bf, config.GetConfig().DebugOptions.CapLink.Key, false)
} }
} }
caStruct := []struct { caStruct := []struct {
@@ -357,31 +361,31 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
bf.WriteUint32(caStruct[i].Unk1) bf.WriteUint32(caStruct[i].Unk1)
ps.Uint8(bf, caStruct[i].Unk2, false) ps.Uint8(bf, caStruct[i].Unk2, false)
} }
bf.WriteUint16(s.server.erupeConfig.DebugOptions.CapLink.Values[2]) bf.WriteUint16(config.GetConfig().DebugOptions.CapLink.Values[2])
bf.WriteUint16(s.server.erupeConfig.DebugOptions.CapLink.Values[3]) bf.WriteUint16(config.GetConfig().DebugOptions.CapLink.Values[3])
bf.WriteUint16(s.server.erupeConfig.DebugOptions.CapLink.Values[4]) bf.WriteUint16(config.GetConfig().DebugOptions.CapLink.Values[4])
if s.server.erupeConfig.DebugOptions.CapLink.Values[2] == 51729 && s.server.erupeConfig.DebugOptions.CapLink.Values[3] == 1 && s.server.erupeConfig.DebugOptions.CapLink.Values[4] == 20000 { if config.GetConfig().DebugOptions.CapLink.Values[2] == 51729 && config.GetConfig().DebugOptions.CapLink.Values[3] == 1 && config.GetConfig().DebugOptions.CapLink.Values[4] == 20000 {
ps.Uint16(bf, fmt.Sprintf(`%s:%d`, s.server.erupeConfig.DebugOptions.CapLink.Host, s.server.erupeConfig.DebugOptions.CapLink.Port), false) ps.Uint16(bf, fmt.Sprintf(`%s:%d`, config.GetConfig().DebugOptions.CapLink.Host, config.GetConfig().DebugOptions.CapLink.Port), false)
} }
bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix())) bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix()))
bf.WriteUint32(0) bf.WriteUint32(0)
tickets := []uint32{ tickets := []uint32{
s.server.erupeConfig.GameplayOptions.MezFesSoloTickets, config.GetConfig().GameplayOptions.MezFesSoloTickets,
s.server.erupeConfig.GameplayOptions.MezFesGroupTickets, config.GetConfig().GameplayOptions.MezFesGroupTickets,
} }
stalls := []uint8{ stalls := []uint8{
10, 3, 6, 9, 4, 8, 5, 7, 10, 3, 6, 9, 4, 8, 5, 7,
} }
if s.server.erupeConfig.GameplayOptions.MezFesSwitchMinigame { if config.GetConfig().GameplayOptions.MezFesSwitchMinigame {
stalls[4] = 2 stalls[4] = 2
} }
// We can just use the start timestamp as the event ID // We can just use the start timestamp as the event ID
bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix())) bf.WriteUint32(uint32(gametime.TimeWeekStart().Unix()))
// Start time // Start time
bf.WriteUint32(uint32(gametime.TimeWeekNext().Add(-time.Duration(s.server.erupeConfig.GameplayOptions.MezFesDuration) * time.Second).Unix())) bf.WriteUint32(uint32(gametime.TimeWeekNext().Add(-time.Duration(config.GetConfig().GameplayOptions.MezFesDuration) * time.Second).Unix()))
// End time // End time
bf.WriteUint32(uint32(gametime.TimeWeekNext().Unix())) bf.WriteUint32(uint32(gametime.TimeWeekNext().Unix()))
bf.WriteUint8(uint8(len(tickets))) bf.WriteUint8(uint8(len(tickets)))

View File

@@ -1,4 +1,4 @@
package signserver package sign
type RespID uint8 type RespID uint8

View File

@@ -1,9 +1,12 @@
package signserver package sign
import ( import (
"database/sql" "database/sql"
"encoding/hex" "encoding/hex"
"erupe-ce/config"
"erupe-ce/utils/db"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt" "fmt"
"net" "net"
@@ -30,7 +33,7 @@ const (
type Session struct { type Session struct {
sync.Mutex sync.Mutex
logger logger.Logger logger logger.Logger
server *Server server *SignServer
rawConn net.Conn rawConn net.Conn
cryptConn *network.CryptConn cryptConn *network.CryptConn
client client client client
@@ -40,7 +43,7 @@ type Session struct {
func (s *Session) work() { func (s *Session) work() {
pkt, err := s.cryptConn.ReadPacket() pkt, err := s.cryptConn.ReadPacket()
if s.server.erupeConfig.DebugOptions.LogInboundMessages { if config.GetConfig().DebugOptions.LogInboundMessages {
fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt)) fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt))
} }
@@ -84,7 +87,7 @@ func (s *Session) handlePacket(pkt []byte) error {
} }
default: default:
s.logger.Warn("Unknown request", zap.String("reqType", reqType)) s.logger.Warn("Unknown request", zap.String("reqType", reqType))
if s.server.erupeConfig.DebugOptions.LogInboundMessages { if config.GetConfig().DebugOptions.LogInboundMessages {
fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt)) fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt))
} }
} }
@@ -108,7 +111,7 @@ func (s *Session) authenticate(username string, password string) {
default: default:
bf.WriteUint8(uint8(resp)) bf.WriteUint8(uint8(resp))
} }
if s.server.erupeConfig.DebugOptions.LogOutboundMessages { if config.GetConfig().DebugOptions.LogOutboundMessages {
fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(bf.Data()), hex.Dump(bf.Data())) fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(bf.Data()), hex.Dump(bf.Data()))
} }
_ = s.cryptConn.SendPacket(bf.Data()) _ = s.cryptConn.SendPacket(bf.Data())
@@ -118,7 +121,11 @@ func (s *Session) handleWIIUSGN(bf *byteframe.ByteFrame) {
_ = bf.ReadBytes(1) _ = bf.ReadBytes(1)
wiiuKey := string(bf.ReadBytes(64)) wiiuKey := string(bf.ReadBytes(64))
var uid uint32 var uid uint32
err := s.server.db.QueryRow(`SELECT id FROM users WHERE wiiu_key = $1`, wiiuKey).Scan(&uid) database, err := db.GetDB() // Capture both return values
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow(`SELECT id FROM users WHERE wiiu_key = $1`, wiiuKey).Scan(&uid)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
s.logger.Info("Unlinked Wii U attempted to authenticate", zap.String("Key", wiiuKey)) s.logger.Info("Unlinked Wii U attempted to authenticate", zap.String("Key", wiiuKey))
@@ -145,7 +152,11 @@ func (s *Session) handlePSSGN(bf *byteframe.ByteFrame) {
} }
s.psn = string(bf.ReadNullTerminatedBytes()) s.psn = string(bf.ReadNullTerminatedBytes())
var uid uint32 var uid uint32
err := s.server.db.QueryRow(`SELECT id FROM users WHERE psn_id = $1`, s.psn).Scan(&uid) database, err := db.GetDB() // Capture both return values
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
err = database.QueryRow(`SELECT id FROM users WHERE psn_id = $1`, s.psn).Scan(&uid)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
s.cryptConn.SendPacket(s.makeSignResponse(0)) s.cryptConn.SendPacket(s.makeSignResponse(0))
@@ -162,9 +173,13 @@ func (s *Session) handlePSNLink(bf *byteframe.ByteFrame) {
credentials := strings.Split(stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()), "\n") credentials := strings.Split(stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()), "\n")
token := string(bf.ReadNullTerminatedBytes()) token := string(bf.ReadNullTerminatedBytes())
uid, resp := s.server.validateLogin(credentials[0], credentials[1]) uid, resp := s.server.validateLogin(credentials[0], credentials[1])
database, err := db.GetDB() // Capture both return values
if err != nil {
s.logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
}
if resp == SIGN_SUCCESS && uid > 0 { if resp == SIGN_SUCCESS && uid > 0 {
var psn string var psn string
err := s.server.db.QueryRow(`SELECT psn_id FROM sign_sessions WHERE token = $1`, token).Scan(&psn) err := database.QueryRow(`SELECT psn_id FROM sign_sessions WHERE token = $1`, token).Scan(&psn)
if err != nil { if err != nil {
s.sendCode(SIGN_ECOGLINK) s.sendCode(SIGN_ECOGLINK)
return return
@@ -172,7 +187,7 @@ func (s *Session) handlePSNLink(bf *byteframe.ByteFrame) {
// Since we check for the psn_id, this will never run // Since we check for the psn_id, this will never run
var exists int var exists int
err = s.server.db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, psn).Scan(&exists) err = database.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, psn).Scan(&exists)
if err != nil { if err != nil {
s.sendCode(SIGN_ECOGLINK) s.sendCode(SIGN_ECOGLINK)
return return
@@ -182,7 +197,7 @@ func (s *Session) handlePSNLink(bf *byteframe.ByteFrame) {
} }
var currentPSN string var currentPSN string
err = s.server.db.QueryRow(`SELECT COALESCE(psn_id, '') FROM users WHERE username = $1`, credentials[0]).Scan(&currentPSN) err = database.QueryRow(`SELECT COALESCE(psn_id, '') FROM users WHERE username = $1`, credentials[0]).Scan(&currentPSN)
if err != nil { if err != nil {
s.sendCode(SIGN_ECOGLINK) s.sendCode(SIGN_ECOGLINK)
return return
@@ -191,7 +206,7 @@ func (s *Session) handlePSNLink(bf *byteframe.ByteFrame) {
return return
} }
_, err = s.server.db.Exec(`UPDATE users SET psn_id = $1 WHERE username = $2`, psn, credentials[0]) _, err = database.Exec(`UPDATE users SET psn_id = $1 WHERE username = $2`, psn, credentials[0])
if err == nil { if err == nil {
s.sendCode(SIGN_SUCCESS) s.sendCode(SIGN_SUCCESS)
return return

View File

@@ -1,4 +1,4 @@
package signserver package sign
import ( import (
"fmt" "fmt"
@@ -6,44 +6,33 @@ import (
"net" "net"
"sync" "sync"
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/logger" "erupe-ce/utils/logger"
"github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
) )
// Config struct allows configuring the server. // SignServer is a MHF sign server.
type Config struct { type SignServer struct {
DB *sqlx.DB
ErupeConfig *_config.Config
}
// Server is a MHF sign server.
type Server struct {
sync.Mutex sync.Mutex
logger logger.Logger logger logger.Logger
erupeConfig *_config.Config
sessions map[int]*Session sessions map[int]*Session
db *sqlx.DB
listener net.Listener listener net.Listener
isShuttingDown bool isShuttingDown bool
} }
// NewServer creates a new Server type. // NewServer creates a new Server type.
func NewServer(config *Config) *Server { func NewServer() *SignServer {
s := &Server{ s := &SignServer{
logger: logger.Get().Named("sign"), logger: logger.Get().Named("sign"),
erupeConfig: config.ErupeConfig,
db: config.DB,
} }
return s return s
} }
// Start starts the server in a new goroutine. // Start starts the server in a new goroutine.
func (server *Server) Start() error { func (server *SignServer) Start() error {
l, err := net.Listen("tcp", fmt.Sprintf(":%d", server.erupeConfig.Sign.Port)) l, err := net.Listen("tcp", fmt.Sprintf(":%d", config.GetConfig().Sign.Port))
if err != nil { if err != nil {
return err return err
} }
@@ -55,7 +44,7 @@ func (server *Server) Start() error {
} }
// Shutdown exits the server gracefully. // Shutdown exits the server gracefully.
func (server *Server) Shutdown() { func (server *SignServer) Shutdown() {
server.logger.Debug("Shutting down...") server.logger.Debug("Shutting down...")
server.Lock() server.Lock()
@@ -66,7 +55,7 @@ func (server *Server) Shutdown() {
server.listener.Close() server.listener.Close()
} }
func (server *Server) acceptClients() { func (server *SignServer) acceptClients() {
for { for {
conn, err := server.listener.Accept() conn, err := server.listener.Accept()
if err != nil { if err != nil {
@@ -86,7 +75,7 @@ func (server *Server) acceptClients() {
} }
} }
func (server *Server) handleConnection(conn net.Conn) { func (server *SignServer) handleConnection(conn net.Conn) {
server.logger.Debug("New connection", zap.String("RemoteAddr", conn.RemoteAddr().String())) server.logger.Debug("New connection", zap.String("RemoteAddr", conn.RemoteAddr().String()))
defer conn.Close() defer conn.Close()

View File

@@ -1,260 +0,0 @@
package signserver
import (
"database/sql"
"errors"
"erupe-ce/utils/mhfcourse"
"erupe-ce/utils/token"
"strings"
"time"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
)
func (server *Server) newUserChara(uid uint32) error {
var numNewChars int
err := server.db.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", uid).Scan(&numNewChars)
if err != nil {
return err
}
// prevent users with an uninitialised character from creating more
if numNewChars >= 1 {
return err
}
_, err = server.db.Exec(`
INSERT INTO characters (
user_id, is_female, is_new_character, name, unk_desc_string,
hr, gr, weapon_type, last_login)
VALUES($1, False, True, '', '', 0, 0, 0, $2)`,
uid,
uint32(time.Now().Unix()),
)
if err != nil {
return err
}
return nil
}
func (server *Server) registerDBAccount(username string, password string) (uint32, error) {
var uid uint32
server.logger.Info("Creating user", zap.String("User", username))
// Create salted hash of user password
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return 0, err
}
err = server.db.QueryRow("INSERT INTO users (username, password, return_expires) VALUES ($1, $2, $3) RETURNING id", username, string(passwordHash), time.Now().Add(time.Hour*24*30)).Scan(&uid)
if err != nil {
return 0, err
}
return uid, nil
}
type character struct {
ID uint32 `db:"id"`
IsFemale bool `db:"is_female"`
IsNewCharacter bool `db:"is_new_character"`
Name string `db:"name"`
UnkDescString string `db:"unk_desc_string"`
HR uint16 `db:"hr"`
GR uint16 `db:"gr"`
WeaponType uint16 `db:"weapon_type"`
LastLogin uint32 `db:"last_login"`
}
func (server *Server) getCharactersForUser(uid uint32) ([]character, error) {
characters := make([]character, 0)
err := server.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hr, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false ORDER BY id", uid)
if err != nil {
return nil, err
}
return characters, nil
}
func (server *Server) getReturnExpiry(uid uint32) time.Time {
var returnExpiry, lastLogin time.Time
server.db.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid)
if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) {
returnExpiry = time.Now().Add(time.Hour * 24 * 30)
server.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
} else {
err := server.db.Get(&returnExpiry, "SELECT return_expires FROM users WHERE id=$1", uid)
if err != nil {
returnExpiry = time.Now()
server.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
}
}
server.db.Exec("UPDATE users SET last_login=$1 WHERE id=$2", time.Now(), uid)
return returnExpiry
}
func (server *Server) getLastCID(uid uint32) uint32 {
var lastPlayed uint32
_ = server.db.QueryRow("SELECT last_character FROM users WHERE id=$1", uid).Scan(&lastPlayed)
return lastPlayed
}
func (server *Server) getUserRights(uid uint32) uint32 {
var rights uint32
if uid != 0 {
_ = server.db.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights)
_, rights = mhfcourse.GetCourseStruct(rights)
}
return rights
}
type members struct {
CID uint32 // Local character ID
ID uint32 `db:"id"`
Name string `db:"name"`
}
func (server *Server) getFriendsForCharacters(chars []character) []members {
friends := make([]members, 0)
for _, char := range chars {
friendsCSV := ""
err := server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", char.ID).Scan(&friendsCSV)
friendsSlice := strings.Split(friendsCSV, ",")
friendQuery := "SELECT id, name FROM characters WHERE id="
for i := 0; i < len(friendsSlice); i++ {
friendQuery += friendsSlice[i]
if i+1 != len(friendsSlice) {
friendQuery += " OR id="
}
}
charFriends := make([]members, 0)
err = server.db.Select(&charFriends, friendQuery)
if err != nil {
continue
}
for i := range charFriends {
charFriends[i].CID = char.ID
}
friends = append(friends, charFriends...)
}
return friends
}
func (server *Server) getGuildmatesForCharacters(chars []character) []members {
guildmates := make([]members, 0)
for _, char := range chars {
var inGuild int
_ = server.db.QueryRow("SELECT count(*) FROM guild_characters WHERE character_id=$1", char.ID).Scan(&inGuild)
if inGuild > 0 {
var guildID int
err := server.db.QueryRow("SELECT guild_id FROM guild_characters WHERE character_id=$1", char.ID).Scan(&guildID)
if err != nil {
continue
}
charGuildmates := make([]members, 0)
err = server.db.Select(&charGuildmates, "SELECT character_id AS id, c.name FROM guild_characters gc JOIN characters c ON c.id = gc.character_id WHERE guild_id=$1 AND character_id!=$2", guildID, char.ID)
if err != nil {
continue
}
for i := range charGuildmates {
charGuildmates[i].CID = char.ID
}
guildmates = append(guildmates, charGuildmates...)
}
}
return guildmates
}
func (server *Server) deleteCharacter(cid int, token string, tokenID uint32) error {
if !server.validateToken(token, tokenID) {
return errors.New("invalid token")
}
var isNew bool
err := server.db.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", cid).Scan(&isNew)
if isNew {
_, err = server.db.Exec("DELETE FROM characters WHERE id = $1", cid)
} else {
_, err = server.db.Exec("UPDATE characters SET deleted = true WHERE id = $1", cid)
}
if err != nil {
return err
}
return nil
}
// Unused
func (server *Server) checkToken(uid uint32) (bool, error) {
var exists int
err := server.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE user_id = $1", uid).Scan(&exists)
if err != nil {
return false, err
}
if exists > 0 {
return true, nil
}
return false, nil
}
func (server *Server) registerUidToken(uid uint32) (uint32, string, error) {
_token := token.Generate(16)
var tid uint32
err := server.db.QueryRow(`INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2) RETURNING id`, uid, _token).Scan(&tid)
return tid, _token, err
}
func (server *Server) registerPsnToken(psn string) (uint32, string, error) {
_token := token.Generate(16)
var tid uint32
err := server.db.QueryRow(`INSERT INTO sign_sessions (psn_id, token) VALUES ($1, $2) RETURNING id`, psn, _token).Scan(&tid)
return tid, _token, err
}
func (server *Server) validateToken(token string, tokenID uint32) bool {
query := `SELECT count(*) FROM sign_sessions WHERE token = $1`
if tokenID > 0 {
query += ` AND id = $2`
}
var exists int
err := server.db.QueryRow(query, token, tokenID).Scan(&exists)
if err != nil || exists == 0 {
return false
}
return true
}
func (server *Server) validateLogin(user string, pass string) (uint32, RespID) {
var uid uint32
var passDB string
err := server.db.QueryRow(`SELECT id, password FROM users WHERE username = $1`, user).Scan(&uid, &passDB)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
server.logger.Info("User not found", zap.String("User", user))
if server.erupeConfig.AutoCreateAccount {
uid, err = server.registerDBAccount(user, pass)
if err == nil {
return uid, SIGN_SUCCESS
} else {
return 0, SIGN_EABORT
}
}
return 0, SIGN_EAUTH
}
return 0, SIGN_EABORT
} else {
if bcrypt.CompareHashAndPassword([]byte(passDB), []byte(pass)) == nil {
var bans int
err = server.db.QueryRow(`SELECT count(*) FROM bans WHERE user_id=$1 AND expires IS NULL`, uid).Scan(&bans)
if err == nil && bans > 0 {
return uid, SIGN_EELIMINATE
}
err = server.db.QueryRow(`SELECT count(*) FROM bans WHERE user_id=$1 AND expires > now()`, uid).Scan(&bans)
if err == nil && bans > 0 {
return uid, SIGN_ESUSPEND
}
return uid, SIGN_SUCCESS
}
return 0, SIGN_EPASS
}
}

77
utils/db/db.go Normal file
View File

@@ -0,0 +1,77 @@
package db
import (
"fmt"
"sync"
"erupe-ce/config"
"erupe-ce/utils/logger"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" // Postgres driver
)
var (
instance *sqlx.DB
once sync.Once
dbLogger logger.Logger
)
// InitDB initializes the database connection pool as a singleton
func InitDB(config *config.Config) (*sqlx.DB, error) {
dbLogger = logger.Get().Named("database")
var err error
once.Do(func() {
// Create the postgres DB pool.
connectString := fmt.Sprintf(
"host='%s' port='%d' user='%s' password='%s' dbname='%s' sslmode=disable",
config.Database.Host,
config.Database.Port,
config.Database.User,
config.Database.Password,
config.Database.Database,
)
instance, err = sqlx.Open("postgres", connectString)
if err != nil {
return // Stop here if there's an error opening the database
}
// Test the DB connection.
err = instance.Ping()
if err != nil {
return // Stop here if there's an error pinging the database
}
dbLogger.Info("Database: Started successfully")
// Clear stale data
if config.DebugOptions.ProxyPort == 0 {
_ = instance.MustExec("DELETE FROM sign_sessions")
}
_ = instance.MustExec("DELETE FROM servers")
_ = instance.MustExec(`UPDATE guild_characters SET treasure_hunt=NULL`)
// Clean the DB if the option is on.
if config.DebugOptions.CleanDB {
dbLogger.Info("Database: Started clearing...")
cleanDB(instance)
dbLogger.Info("Database: Finished clearing")
}
})
return instance, err
}
func GetDB() (*sqlx.DB, error) {
if instance == nil {
return nil, fmt.Errorf("database not initialized")
}
return instance, nil
}
// 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 users")
}

View File

@@ -1,7 +1,7 @@
package mhfcourse package mhfcourse
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"math" "math"
"sort" "sort"
"time" "time"
@@ -68,7 +68,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) {
var resp []Course var resp []Course
for _, c := range _config.ErupeConfig.DefaultCourses { for _, c := range config.GetConfig().DefaultCourses {
resp = append(resp, Course{ID: c}) resp = append(resp, Course{ID: c})
} }
s := Courses() s := Courses()

View File

@@ -1,7 +1,7 @@
package mhfitem package mhfitem
import ( import (
_config "erupe-ce/config" "erupe-ce/config"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/token" "erupe-ce/utils/token"
) )
@@ -114,7 +114,7 @@ func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
equipment.Decorations[i].ItemID = bf.ReadUint16() equipment.Decorations[i].ItemID = bf.ReadUint16()
} }
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ { for j := 0; j < 3; j++ {
equipment.Sigils[i].Effects[j].ID = bf.ReadUint16() equipment.Sigils[i].Effects[j].ID = bf.ReadUint16()
@@ -128,7 +128,7 @@ func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
equipment.Sigils[i].Unk3 = bf.ReadUint8() equipment.Sigils[i].Unk3 = bf.ReadUint8()
} }
} }
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
equipment.Unk1 = bf.ReadUint16() equipment.Unk1 = bf.ReadUint16()
} }
return equipment return equipment
@@ -144,7 +144,7 @@ func (e MHFEquipment) ToBytes() []byte {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
bf.WriteUint16(e.Decorations[i].ItemID) bf.WriteUint16(e.Decorations[i].ItemID)
} }
if _config.ErupeConfig.ClientID >= _config.G1 { if config.GetConfig().ClientID >= config.G1 {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ { for j := 0; j < 3; j++ {
bf.WriteUint16(e.Sigils[i].Effects[j].ID) bf.WriteUint16(e.Sigils[i].Effects[j].ID)
@@ -158,7 +158,7 @@ func (e MHFEquipment) ToBytes() []byte {
bf.WriteUint8(e.Sigils[i].Unk3) bf.WriteUint8(e.Sigils[i].Unk3)
} }
} }
if _config.ErupeConfig.ClientID >= _config.Z1 { if config.GetConfig().ClientID >= config.Z1 {
bf.WriteUint16(e.Unk1) bf.WriteUint16(e.Unk1)
} }
return bf.Data() return bf.Data()