mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-02-06 10:06:53 +01:00
Merge branch 'main' into feature/diva
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO fpoint_items (item_type, item_id, quantity, fpoints, trade_type) VALUES
|
||||
(7,8895,1,500,0),
|
||||
(7,8891,1,300,0),
|
||||
@@ -384,4 +386,6 @@ INSERT INTO fpoint_items (item_type, item_id, quantity, fpoints, trade_type) VAL
|
||||
(7,16448,1,3,0),
|
||||
(7,16449,1,3,0),
|
||||
(7,16348,1,3,0),
|
||||
(7,16349,1,3,0)
|
||||
(7,16349,1,3,0);
|
||||
|
||||
END;
|
||||
16
config.json
16
config.json
@@ -3,9 +3,10 @@
|
||||
"BinPath": "bin",
|
||||
"Language": "en",
|
||||
"DisableSoftCrash": false,
|
||||
"FeaturedWeapons": 1,
|
||||
"HideLoginNotice": true,
|
||||
"LoginNotice": "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.1!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you.",
|
||||
"LoginNotices": [
|
||||
"<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.2!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you."
|
||||
],
|
||||
"PatchServerManifest": "",
|
||||
"PatchServerFile": "",
|
||||
"ScreenshotAPIURL": "",
|
||||
@@ -31,6 +32,17 @@
|
||||
"OutputDir": "savedata"
|
||||
}
|
||||
},
|
||||
"GameplayOptions": {
|
||||
"FeaturedWeapons": 1,
|
||||
"MaximumNP": 100000,
|
||||
"MaximumRP": 50000,
|
||||
"DisableLoginBoost": false,
|
||||
"DisableBoostTime": false,
|
||||
"BoostTimeDuration": 120,
|
||||
"GuildMealDuration": 60,
|
||||
"BonusQuestAllowance": 3,
|
||||
"DailyQuestAllowance": 1
|
||||
},
|
||||
"Discord": {
|
||||
"Enabled": false,
|
||||
"BotToken": "",
|
||||
|
||||
@@ -15,25 +15,25 @@ type Config struct {
|
||||
Host string `mapstructure:"Host"`
|
||||
BinPath string `mapstructure:"BinPath"`
|
||||
Language string
|
||||
DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically
|
||||
FeaturedWeapons int // Number of Active Feature weapons to generate daily
|
||||
HideLoginNotice bool // Hide the Erupe notice on login
|
||||
LoginNotice string // MHFML string of the login notice displayed
|
||||
PatchServerManifest string // Manifest patch server override
|
||||
PatchServerFile string // File patch server override
|
||||
ScreenshotAPIURL string // Destination for screenshots uploaded to BBS
|
||||
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
|
||||
DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically
|
||||
HideLoginNotice bool // Hide the Erupe notice on login
|
||||
LoginNotices []string // MHFML string of the login notices displayed
|
||||
PatchServerManifest string // Manifest patch server override
|
||||
PatchServerFile string // File patch server override
|
||||
ScreenshotAPIURL string // Destination for screenshots uploaded to BBS
|
||||
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
|
||||
DevMode bool
|
||||
|
||||
DevModeOptions DevModeOptions
|
||||
Discord Discord
|
||||
Commands []Command
|
||||
Courses []Course
|
||||
Database Database
|
||||
Sign Sign
|
||||
SignV2 SignV2
|
||||
Channel Channel
|
||||
Entrance Entrance
|
||||
DevModeOptions DevModeOptions
|
||||
GameplayOptions GameplayOptions
|
||||
Discord Discord
|
||||
Commands []Command
|
||||
Courses []Course
|
||||
Database Database
|
||||
Sign Sign
|
||||
SignV2 SignV2
|
||||
Channel Channel
|
||||
Entrance Entrance
|
||||
}
|
||||
|
||||
// DevModeOptions holds various debug/temporary options for use while developing Erupe.
|
||||
@@ -60,6 +60,19 @@ type SaveDumpOptions struct {
|
||||
OutputDir string
|
||||
}
|
||||
|
||||
// GameplayOptions has various gameplay modifiers
|
||||
type GameplayOptions struct {
|
||||
FeaturedWeapons int // Number of Active Feature weapons to generate daily
|
||||
MaximumNP int // Maximum number of NP held by a player
|
||||
MaximumRP uint16 // Maximum number of RP held by a player
|
||||
DisableLoginBoost bool // Disables the Login Boost system
|
||||
DisableBoostTime bool // Disables the daily NetCafe Boost Time
|
||||
BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for
|
||||
GuildMealDuration int // The number of minutes a Guild Meal can be activated for after cooking
|
||||
BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily
|
||||
DailyQuestAllowance uint32 // Number of Daily Quests to allow daily
|
||||
}
|
||||
|
||||
// Discord holds the discord integration config.
|
||||
type Discord struct {
|
||||
Enabled bool
|
||||
|
||||
6
go.mod
6
go.mod
@@ -8,18 +8,16 @@ require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/jmoiron/sqlx v1.3.4
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96
|
||||
github.com/spf13/viper v1.8.1
|
||||
go.uber.org/zap v1.18.1
|
||||
golang.org/x/crypto v0.1.0
|
||||
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
|
||||
golang.org/x/text v0.4.0
|
||||
golang.org/x/text v0.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
@@ -32,7 +30,7 @@ require (
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
13
go.sum
13
go.sum
@@ -94,8 +94,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -229,8 +227,6 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96 h1:BanNeULiV7hOXjHPUQt3tgF6qVHGZ0uLMnCr0WZ5CTk=
|
||||
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96/go.mod h1:NuxNqEW5jNyYkZ5WSBB70WQXtRKY1jUPMzX74wr5JFo=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@@ -430,8 +426,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -440,8 +436,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -496,7 +492,6 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
81
main.go
81
main.go
@@ -5,6 +5,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/debug"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -29,13 +30,31 @@ func cleanDB(db *sqlx.DB) {
|
||||
_ = db.MustExec("DELETE FROM users")
|
||||
}
|
||||
|
||||
var Commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
for _, setting := range info.Settings {
|
||||
if setting.Key == "vcs.revision" {
|
||||
return setting.Value[:7]
|
||||
}
|
||||
}
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
zapLogger, _ := zap.NewDevelopment()
|
||||
|
||||
var zapLogger *zap.Logger
|
||||
if config.ErupeConfig.DevMode {
|
||||
zapLogger, _ = zap.NewDevelopment()
|
||||
} else {
|
||||
zapLogger, _ = zap.NewProduction()
|
||||
}
|
||||
|
||||
defer zapLogger.Sync()
|
||||
logger := zapLogger.Named("main")
|
||||
|
||||
logger.Info("Starting Erupe (9.2b)")
|
||||
logger.Info(fmt.Sprintf("Starting Erupe (9.2b-%s)", Commit()))
|
||||
|
||||
if config.ErupeConfig.Database.Password == "" {
|
||||
preventClose("Database password is blank")
|
||||
@@ -64,20 +83,20 @@ func main() {
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to create Discord bot: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error()))
|
||||
}
|
||||
|
||||
// Discord bot
|
||||
err = bot.Start()
|
||||
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to start Discord bot: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error()))
|
||||
}
|
||||
|
||||
discordBot = bot
|
||||
logger.Info("Discord bot is enabled")
|
||||
logger.Info("Discord: Started successfully")
|
||||
} else {
|
||||
logger.Info("Discord bot is disabled")
|
||||
logger.Info("Discord: Disabled")
|
||||
}
|
||||
|
||||
// Create the postgres DB pool.
|
||||
@@ -92,15 +111,15 @@ func main() {
|
||||
|
||||
db, err := sqlx.Open("postgres", connectString)
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to open SQL database: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Database: Failed to open, %s", err.Error()))
|
||||
}
|
||||
|
||||
// Test the DB connection.
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to ping database: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Database: Failed to ping, %s", err.Error()))
|
||||
}
|
||||
logger.Info("Connected to database")
|
||||
logger.Info("Database: Started successfully")
|
||||
|
||||
// Clear stale data
|
||||
_ = db.MustExec("DELETE FROM sign_sessions")
|
||||
@@ -108,11 +127,13 @@ func main() {
|
||||
|
||||
// Clean the DB if the option is on.
|
||||
if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB {
|
||||
logger.Info("Cleaning DB")
|
||||
logger.Info("Database: Started clearing...")
|
||||
cleanDB(db)
|
||||
logger.Info("Done cleaning DB")
|
||||
logger.Info("Database: Finished clearing")
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("Server Time: %s", channelserver.TimeAdjusted().String()))
|
||||
|
||||
// Now start our server(s).
|
||||
|
||||
// Entrance server.
|
||||
@@ -127,9 +148,11 @@ func main() {
|
||||
})
|
||||
err = entranceServer.Start()
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Entrance: Failed to start, %s", err.Error()))
|
||||
}
|
||||
logger.Info("Started entrance server")
|
||||
logger.Info("Entrance: Started successfully")
|
||||
} else {
|
||||
logger.Info("Entrance: Disabled")
|
||||
}
|
||||
|
||||
// Sign server.
|
||||
@@ -144,9 +167,11 @@ func main() {
|
||||
})
|
||||
err = signServer.Start()
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Sign: Failed to start, %s", err.Error()))
|
||||
}
|
||||
logger.Info("Started sign server")
|
||||
logger.Info("Sign: Started successfully")
|
||||
} else {
|
||||
logger.Info("Sign: Disabled")
|
||||
}
|
||||
|
||||
// New Sign server
|
||||
@@ -160,9 +185,11 @@ func main() {
|
||||
})
|
||||
err = newSignServer.Start()
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to start sign-v2 server: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("SignV2: Failed to start, %s", err.Error()))
|
||||
}
|
||||
logger.Info("Started new sign server")
|
||||
logger.Info("SignV2: Started successfully")
|
||||
} else {
|
||||
logger.Info("SignV2: Disabled")
|
||||
}
|
||||
|
||||
var channels []*channelserver.Server
|
||||
@@ -172,7 +199,7 @@ func main() {
|
||||
si := 0
|
||||
ci := 0
|
||||
count := 1
|
||||
for _, ee := range config.ErupeConfig.Entrance.Entries {
|
||||
for j, ee := range config.ErupeConfig.Entrance.Entries {
|
||||
for i, ce := range ee.Channels {
|
||||
sid := (4096 + si*256) + (16 + ci)
|
||||
c := *channelserver.NewServer(&channelserver.Config{
|
||||
@@ -188,13 +215,14 @@ func main() {
|
||||
c.IP = ee.IP
|
||||
}
|
||||
c.Port = ce.Port
|
||||
c.GlobalID = fmt.Sprintf("%02d%02d", j+1, i+1)
|
||||
err = c.Start()
|
||||
if err != nil {
|
||||
preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error()))
|
||||
preventClose(fmt.Sprintf("Channel: Failed to start, %s", err.Error()))
|
||||
} else {
|
||||
channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, season, current_players, world_name, world_description, land) VALUES (%d, %d, 0, '%s', '%s', %d);`, sid, si%3, ee.Name, ee.Description, i+1)
|
||||
channels = append(channels, &c)
|
||||
logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port))
|
||||
logger.Info(fmt.Sprintf("Channel %d (%d): Started successfully", count, ce.Port))
|
||||
ci++
|
||||
count++
|
||||
}
|
||||
@@ -211,12 +239,23 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("Finished starting Erupe")
|
||||
|
||||
// Wait for exit or interrupt with ctrl+C.
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
<-c
|
||||
|
||||
logger.Info("Trying to shutdown gracefully")
|
||||
if !config.ErupeConfig.DisableSoftCrash {
|
||||
for i := 0; i < 10; i++ {
|
||||
message := fmt.Sprintf("Shutting down in %d...", 10-i)
|
||||
for _, c := range channels {
|
||||
c.BroadcastChatMessage(message)
|
||||
}
|
||||
logger.Info(message)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
if config.ErupeConfig.Channel.Enabled {
|
||||
for _, c := range channels {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"errors"
|
||||
|
||||
"erupe-ce/network/clientctx"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// MsgSysLockGlobalSema represents the MSG_SYS_LOCK_GLOBAL_SEMA
|
||||
type MsgSysLockGlobalSema struct {
|
||||
AckHandle uint32
|
||||
UserIDLength uint16
|
||||
ServerChannelIDLength uint16
|
||||
UserIDLength uint16
|
||||
ServerChannelIDLength uint16
|
||||
UserIDString string
|
||||
ServerChannelIDString string
|
||||
}
|
||||
|
||||
12
patch-schema/login-boost.sql
Normal file
12
patch-schema/login-boost.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
BEGIN;
|
||||
|
||||
DROP TABLE IF EXISTS public.login_boost_state;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.login_boost (
|
||||
char_id INTEGER,
|
||||
week_req INTEGER,
|
||||
expiration TIMESTAMP WITH TIME ZONE,
|
||||
reset TIMESTAMP WITH TIME ZONE
|
||||
);
|
||||
|
||||
END;
|
||||
6
patch-schema/mezfes-save.sql
Normal file
6
patch-schema/mezfes-save.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE public.characters
|
||||
ADD COLUMN mezfes BYTEA;
|
||||
|
||||
END;
|
||||
69
patch-schema/time-fix.sql
Normal file
69
patch-schema/time-fix.sql
Normal file
@@ -0,0 +1,69 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ALTER COLUMN guild_post_checked TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ALTER COLUMN boost_time TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ALTER COLUMN cafe_reset TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.distribution
|
||||
ALTER COLUMN deadline TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.events
|
||||
ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.feature_weapon
|
||||
ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guild_alliances
|
||||
ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guild_applications
|
||||
ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guild_characters
|
||||
ALTER COLUMN joined_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guild_posts
|
||||
ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guilds
|
||||
ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.mail
|
||||
ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.stamps
|
||||
ALTER COLUMN hl_next TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.stamps
|
||||
ALTER COLUMN ex_next TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.titles
|
||||
ALTER COLUMN unlocked_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.titles
|
||||
ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.users
|
||||
ALTER COLUMN last_login TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.users
|
||||
ALTER COLUMN return_expires TYPE TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guild_meals
|
||||
DROP COLUMN expires;
|
||||
|
||||
ALTER TABLE IF EXISTS public.guild_meals
|
||||
ADD COLUMN created_at TIMESTAMP WITH TIME ZONE;
|
||||
|
||||
END;
|
||||
@@ -3,6 +3,7 @@ package channelserver
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
ps "erupe-ce/common/pascalstring"
|
||||
"erupe-ce/common/stringsupport"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -144,7 +145,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
updateRights(s)
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // Unix timestamp
|
||||
bf.WriteUint32(uint32(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)
|
||||
if err != nil {
|
||||
@@ -156,7 +157,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = s.server.db.Exec("UPDATE characters SET last_login=$1 WHERE id=$2", Time_Current().Unix(), s.charID)
|
||||
_, err = s.server.db.Exec("UPDATE characters SET last_login=$1 WHERE id=$2", TimeAdjusted().Unix(), s.charID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -216,7 +217,7 @@ func logoutPlayer(s *Session) {
|
||||
var timePlayed int
|
||||
var sessionTime int
|
||||
_ = s.server.db.QueryRow("SELECT time_played FROM characters WHERE id = $1", s.charID).Scan(&timePlayed)
|
||||
sessionTime = int(Time_Current_Adjusted().Unix()) - int(s.sessionStart)
|
||||
sessionTime = int(TimeAdjusted().Unix()) - int(s.sessionStart)
|
||||
timePlayed += sessionTime
|
||||
|
||||
var rpGained int
|
||||
@@ -258,8 +259,8 @@ func logoutPlayer(s *Session) {
|
||||
return
|
||||
}
|
||||
saveData.RP += uint16(rpGained)
|
||||
if saveData.RP >= 50000 {
|
||||
saveData.RP = 50000
|
||||
if saveData.RP >= s.server.erupeConfig.GameplayOptions.MaximumRP {
|
||||
saveData.RP = s.server.erupeConfig.GameplayOptions.MaximumRP
|
||||
}
|
||||
saveData.Save(s)
|
||||
}
|
||||
@@ -276,7 +277,7 @@ func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
resp := &mhfpacket.MsgSysTime{
|
||||
GetRemoteTime: false,
|
||||
Timestamp: uint32(Time_Current_Adjusted().Unix()), // JP timezone
|
||||
Timestamp: uint32(TimeAdjusted().Unix()), // JP timezone
|
||||
}
|
||||
s.QueueSendMHF(resp)
|
||||
}
|
||||
@@ -314,25 +315,30 @@ func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysLockGlobalSema)
|
||||
|
||||
var sgid string
|
||||
for _, channel := range s.server.Channels {
|
||||
for id := range channel.stages {
|
||||
if strings.HasSuffix(id, pkt.UserIDString) {
|
||||
sgid = channel.GlobalID
|
||||
}
|
||||
}
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
// Unk
|
||||
// 0x00 when no ID sent
|
||||
// 0x02 when ID sent
|
||||
if pkt.ServerChannelIDLength == 1 {
|
||||
bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x01, 0x00})
|
||||
if len(sgid) > 0 && sgid != s.server.GlobalID {
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
ps.Uint16(bf, sgid, false)
|
||||
} else {
|
||||
bf.WriteUint8(0x02)
|
||||
bf.WriteUint8(0x00) // Unk
|
||||
bf.WriteUint16(uint16(pkt.ServerChannelIDLength))
|
||||
bf.WriteBytes([]byte(pkt.ServerChannelIDString))
|
||||
bf.WriteUint8(2)
|
||||
bf.WriteUint8(0)
|
||||
ps.Uint16(bf, pkt.ServerChannelIDString, false)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgSysUnlockGlobalSema(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysUnlockGlobalSema)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 8))
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
func handleMsgSysUpdateRight(s *Session, p mhfpacket.MHFPacket) {}
|
||||
@@ -1505,7 +1511,7 @@ func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
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)
|
||||
if Time_Current_Adjusted().After(dailyTime) {
|
||||
if TimeAdjusted().After(dailyTime) {
|
||||
s.server.db.Exec("UPDATE characters SET bonus_quests = 0, daily_quests = 0 WHERE id=$1", s.charID)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,8 @@ func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfCheckDailyCafepoint)
|
||||
|
||||
// get next midday
|
||||
var t = Time_static()
|
||||
year, month, day := t.Date()
|
||||
midday := time.Date(year, month, day, 12, 0, 0, 0, t.Location())
|
||||
if t.After(midday) {
|
||||
midday := TimeMidnight().Add(12 * time.Hour)
|
||||
if TimeAdjusted().After(midday) {
|
||||
midday = midday.Add(24 * time.Hour)
|
||||
}
|
||||
|
||||
@@ -54,11 +51,11 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
var bondBonus, bonusQuests, dailyQuests uint32
|
||||
bf := byteframe.NewByteFrame()
|
||||
if t.After(dailyTime) {
|
||||
if midday.After(dailyTime) {
|
||||
addPointNetcafe(s, 5)
|
||||
bondBonus = 5 // Bond point bonus quests
|
||||
bonusQuests = 3 // HRP bonus quests?
|
||||
dailyQuests = 1 // Daily quests
|
||||
bondBonus = 5 // Bond point bonus quests
|
||||
bonusQuests = s.server.erupeConfig.GameplayOptions.BonusQuestAllowance
|
||||
dailyQuests = s.server.erupeConfig.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)
|
||||
bf.WriteBool(true) // Success?
|
||||
} else {
|
||||
@@ -80,7 +77,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
|
||||
cafeReset = TimeWeekNext()
|
||||
s.server.db.Exec(`UPDATE characters SET cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID)
|
||||
}
|
||||
if Time_Current_Adjusted().After(cafeReset) {
|
||||
if TimeAdjusted().After(cafeReset) {
|
||||
cafeReset = TimeWeekNext()
|
||||
s.server.db.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)
|
||||
@@ -92,7 +89,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
|
||||
panic(err)
|
||||
}
|
||||
if s.FindCourse("NetCafe").ID != 0 || s.FindCourse("N").ID != 0 {
|
||||
cafeTime = uint32(Time_Current_Adjusted().Unix()) - uint32(s.sessionStart) + cafeTime
|
||||
cafeTime = uint32(TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime
|
||||
}
|
||||
bf.WriteUint32(cafeTime) // Total cafe time
|
||||
bf.WriteUint16(0)
|
||||
@@ -142,7 +139,7 @@ func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
resp := byteframe.NewByteFrame()
|
||||
resp.WriteUint32(0)
|
||||
resp.WriteUint32(uint32(time.Now().Unix()))
|
||||
resp.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
resp.WriteUint32(count)
|
||||
resp.WriteBytes(bf.Data())
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
@@ -165,7 +162,7 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {
|
||||
SELECT ch.cafe_time + $2
|
||||
FROM characters ch
|
||||
WHERE ch.id = $1
|
||||
) >= time_req`, s.charID, Time_Current_Adjusted().Unix()-s.sessionStart)
|
||||
) >= time_req`, s.charID, TimeAdjusted().Unix()-s.sessionStart)
|
||||
if err != nil {
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
} else {
|
||||
@@ -210,8 +207,8 @@ func addPointNetcafe(s *Session, p int) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if points+p > 100000 {
|
||||
points = 100000
|
||||
if points+p > s.server.erupeConfig.GameplayOptions.MaximumNP {
|
||||
points = s.server.erupeConfig.GameplayOptions.MaximumNP
|
||||
} else {
|
||||
points += p
|
||||
}
|
||||
@@ -222,7 +219,12 @@ func addPointNetcafe(s *Session, p int) error {
|
||||
func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfStartBoostTime)
|
||||
bf := byteframe.NewByteFrame()
|
||||
boostLimit := Time_Current_Adjusted().Add(100 * time.Minute)
|
||||
boostLimit := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.BoostTimeDuration) * time.Minute)
|
||||
if s.server.erupeConfig.GameplayOptions.DisableBoostTime {
|
||||
bf.WriteUint32(0)
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
return
|
||||
}
|
||||
s.server.db.Exec("UPDATE characters SET boost_time=$1 WHERE id=$2", boostLimit, s.charID)
|
||||
bf.WriteUint32(uint32(boostLimit.Unix()))
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
@@ -255,7 +257,7 @@ func handleMsgMhfGetBoostRight(s *Session, p mhfpacket.MHFPacket) {
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
return
|
||||
}
|
||||
if boostLimit.Unix() > Time_Current_Adjusted().Unix() {
|
||||
if boostLimit.After(TimeAdjusted()) {
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
|
||||
} else {
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x02})
|
||||
|
||||
@@ -38,16 +38,18 @@ var commands map[string]config.Command
|
||||
|
||||
func init() {
|
||||
commands = make(map[string]config.Command)
|
||||
zapLogger, _ := zap.NewDevelopment()
|
||||
zapConfig := zap.NewDevelopmentConfig()
|
||||
zapConfig.DisableCaller = true
|
||||
zapLogger, _ := zapConfig.Build()
|
||||
defer zapLogger.Sync()
|
||||
logger := zapLogger.Named("commands")
|
||||
cmds := config.ErupeConfig.Commands
|
||||
for _, cmd := range cmds {
|
||||
commands[cmd.Name] = cmd
|
||||
if cmd.Enabled {
|
||||
logger.Info(fmt.Sprintf("%s command is enabled, prefix: %s", cmd.Name, cmd.Prefix))
|
||||
logger.Info(fmt.Sprintf("Command %s: Enabled, prefix: %s", cmd.Name, cmd.Prefix))
|
||||
} else {
|
||||
logger.Info(fmt.Sprintf("%s command is disabled", cmd.Name))
|
||||
logger.Info(fmt.Sprintf("Command %s: Disabled", cmd.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func cleanupDiva(s *Session) {
|
||||
|
||||
func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
||||
timestamps := make([]uint32, 6)
|
||||
midnight := Time_Current_Midnight()
|
||||
midnight := TimeMidnight()
|
||||
if debug && start <= 3 {
|
||||
midnight := uint32(midnight.Unix())
|
||||
switch start {
|
||||
@@ -50,7 +50,7 @@ func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
||||
}
|
||||
return timestamps
|
||||
}
|
||||
if start == 0 || Time_Current_Adjusted().Unix() > int64(start)+2977200 {
|
||||
if start == 0 || TimeAdjusted().Unix() > int64(start)+2977200 {
|
||||
cleanupDiva(s)
|
||||
// Generate a new diva defense, starting midnight tomorrow
|
||||
start = uint32(midnight.Add(24 * time.Hour).Unix())
|
||||
|
||||
@@ -61,29 +61,26 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
|
||||
|
||||
var features []activeFeature
|
||||
rows, _ := s.server.db.Queryx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1 OR start_time=$2`, Time_Current_Midnight().Add(-24*time.Hour), Time_Current_Midnight())
|
||||
for rows.Next() {
|
||||
var feature activeFeature
|
||||
rows.StructScan(&feature)
|
||||
features = append(features, feature)
|
||||
times := []time.Time{
|
||||
TimeMidnight().Add(-24 * time.Hour),
|
||||
TimeMidnight(),
|
||||
TimeMidnight().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
if len(features) < 2 {
|
||||
if len(features) == 0 {
|
||||
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
|
||||
feature.StartTime = Time_Current_Midnight().Add(-24 * time.Hour)
|
||||
features = append(features, feature)
|
||||
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
|
||||
for _, t := range times {
|
||||
var temp activeFeature
|
||||
err := s.server.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, t).StructScan(&temp)
|
||||
if err != nil || temp.StartTime.IsZero() {
|
||||
temp = generateFeatureWeapons(s.server.erupeConfig.GameplayOptions.FeaturedWeapons)
|
||||
temp.StartTime = t
|
||||
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures)
|
||||
}
|
||||
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
|
||||
feature.StartTime = Time_Current_Midnight()
|
||||
features = append(features, feature)
|
||||
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
|
||||
features = append(features, temp)
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(2)
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
|
||||
bf.WriteUint8(uint8(len(features)))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Add(-5 * time.Minute).Unix()))
|
||||
for _, feature := range features {
|
||||
bf.WriteUint32(uint32(feature.StartTime.Unix()))
|
||||
bf.WriteUint32(feature.ActiveFeatures)
|
||||
@@ -119,129 +116,97 @@ func generateFeatureWeapons(count int) activeFeature {
|
||||
}
|
||||
|
||||
type loginBoost struct {
|
||||
WeekReq, WeekCount uint8
|
||||
Available bool
|
||||
Expiration uint32
|
||||
WeekReq uint8 `db:"week_req"`
|
||||
WeekCount uint8
|
||||
Active bool
|
||||
Expiration time.Time `db:"expiration"`
|
||||
Reset time.Time `db:"reset"`
|
||||
}
|
||||
|
||||
func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus)
|
||||
|
||||
var loginBoostStatus []loginBoost
|
||||
insert := false
|
||||
boostState, err := s.server.db.Query("SELECT week_req, week_count, available, end_time FROM login_boost_state WHERE char_id=$1 ORDER BY week_req ASC", s.charID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
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)
|
||||
if err != nil || s.server.erupeConfig.GameplayOptions.DisableLoginBoost {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35))
|
||||
return
|
||||
}
|
||||
for boostState.Next() {
|
||||
var boost loginBoost
|
||||
err = boostState.Scan(&boost.WeekReq, &boost.WeekCount, &boost.Available, &boost.Expiration)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
for rows.Next() {
|
||||
var temp loginBoost
|
||||
rows.StructScan(&temp)
|
||||
loginBoosts = append(loginBoosts, temp)
|
||||
}
|
||||
if len(loginBoosts) == 0 {
|
||||
temp := TimeWeekStart()
|
||||
loginBoosts = []loginBoost{
|
||||
{WeekReq: 1, Expiration: temp},
|
||||
{WeekReq: 2, Expiration: temp},
|
||||
{WeekReq: 3, Expiration: temp},
|
||||
{WeekReq: 4, Expiration: temp},
|
||||
{WeekReq: 5, Expiration: temp},
|
||||
}
|
||||
loginBoostStatus = append(loginBoostStatus, boost)
|
||||
}
|
||||
if len(loginBoostStatus) == 0 {
|
||||
// create default Entries (should only been week 1 with )
|
||||
insert = true
|
||||
loginBoostStatus = []loginBoost{
|
||||
{
|
||||
WeekReq: 1, // weeks needed
|
||||
WeekCount: 0, // weeks passed
|
||||
Available: true, // available
|
||||
Expiration: 0, //uint32(t.Add(120 * time.Minute).Unix()), // uncomment to enable permanently
|
||||
},
|
||||
{
|
||||
WeekReq: 2,
|
||||
WeekCount: 0,
|
||||
Available: true,
|
||||
Expiration: 0,
|
||||
},
|
||||
{
|
||||
WeekReq: 3,
|
||||
WeekCount: 0,
|
||||
Available: true,
|
||||
Expiration: 0,
|
||||
},
|
||||
{
|
||||
WeekReq: 4,
|
||||
WeekCount: 0,
|
||||
Available: true,
|
||||
Expiration: 0,
|
||||
},
|
||||
{
|
||||
WeekReq: 5,
|
||||
WeekCount: 0,
|
||||
Available: true,
|
||||
Expiration: 0,
|
||||
},
|
||||
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{})
|
||||
}
|
||||
}
|
||||
resp := byteframe.NewByteFrame()
|
||||
CurrentWeek := Time_Current_Week_uint8()
|
||||
for d := range loginBoostStatus {
|
||||
if CurrentWeek == 1 && loginBoostStatus[d].WeekCount <= 5 {
|
||||
loginBoostStatus[d].WeekCount = 0
|
||||
|
||||
for _, boost := range loginBoosts {
|
||||
// Reset if next week
|
||||
if !boost.Reset.IsZero() && boost.Reset.Before(TimeAdjusted()) {
|
||||
boost.Expiration = TimeWeekStart()
|
||||
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)
|
||||
}
|
||||
if loginBoostStatus[d].WeekReq == CurrentWeek || loginBoostStatus[d].WeekCount != 0 {
|
||||
loginBoostStatus[d].WeekCount = CurrentWeek
|
||||
|
||||
boost.WeekCount = uint8((TimeAdjusted().Unix()-boost.Expiration.Unix())/604800 + 1)
|
||||
|
||||
if boost.WeekCount >= boost.WeekReq {
|
||||
boost.Active = true
|
||||
boost.WeekCount = boost.WeekReq
|
||||
}
|
||||
if !loginBoostStatus[d].Available && loginBoostStatus[d].WeekCount >= loginBoostStatus[d].WeekReq && uint32(time.Now().In(time.FixedZone("UTC+1", 1*60*60)).Unix()) >= loginBoostStatus[d].Expiration {
|
||||
loginBoostStatus[d].Expiration = 1
|
||||
|
||||
// Show reset timer on expired boosts
|
||||
if boost.Reset.After(TimeAdjusted()) {
|
||||
boost.Active = true
|
||||
boost.WeekCount = 0
|
||||
}
|
||||
if !insert {
|
||||
_, err := s.server.db.Exec(`UPDATE login_boost_state SET week_count=$1, end_time=$2 WHERE char_id=$3 AND week_req=$4`, loginBoostStatus[d].WeekCount, loginBoostStatus[d].Expiration, s.charID, loginBoostStatus[d].WeekReq)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bf.WriteUint8(boost.WeekReq)
|
||||
bf.WriteBool(boost.Active)
|
||||
bf.WriteUint8(boost.WeekCount)
|
||||
if !boost.Reset.IsZero() {
|
||||
bf.WriteUint32(uint32(boost.Expiration.Unix()))
|
||||
} else {
|
||||
bf.WriteUint32(0)
|
||||
}
|
||||
}
|
||||
for _, v := range loginBoostStatus {
|
||||
if insert {
|
||||
_, err := s.server.db.Exec(`INSERT INTO login_boost_state (char_id, week_req, week_count, available, end_time) VALUES ($1,$2,$3,$4,$5)`, s.charID, v.WeekReq, v.WeekCount, v.Available, v.Expiration)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
resp.WriteUint8(v.WeekReq)
|
||||
resp.WriteUint8(v.WeekCount)
|
||||
resp.WriteBool(v.Available)
|
||||
resp.WriteUint32(v.Expiration)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {
|
||||
// Directly interacts with MhfGetKeepLoginBoostStatus
|
||||
// TODO: make these states persistent on a per character basis
|
||||
pkt := p.(*mhfpacket.MsgMhfUseKeepLoginBoost)
|
||||
var t = time.Now().In(time.FixedZone("UTC+1", 1*60*60))
|
||||
resp := byteframe.NewByteFrame()
|
||||
resp.WriteUint8(0)
|
||||
|
||||
// response is end timestamp based on input
|
||||
var expiration time.Time
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(0)
|
||||
switch pkt.BoostWeekUsed {
|
||||
case 1:
|
||||
t = t.Add(120 * time.Minute)
|
||||
resp.WriteUint32(uint32(t.Unix()))
|
||||
case 2:
|
||||
t = t.Add(240 * time.Minute)
|
||||
resp.WriteUint32(uint32(t.Unix()))
|
||||
fallthrough
|
||||
case 3:
|
||||
t = t.Add(120 * time.Minute)
|
||||
resp.WriteUint32(uint32(t.Unix()))
|
||||
expiration = TimeAdjusted().Add(120 * time.Minute)
|
||||
case 4:
|
||||
t = t.Add(180 * time.Minute)
|
||||
resp.WriteUint32(uint32(t.Unix()))
|
||||
expiration = TimeAdjusted().Add(180 * time.Minute)
|
||||
case 2:
|
||||
fallthrough
|
||||
case 5:
|
||||
t = t.Add(240 * time.Minute)
|
||||
resp.WriteUint32(uint32(t.Unix()))
|
||||
expiration = TimeAdjusted().Add(240 * time.Minute)
|
||||
}
|
||||
_, err := s.server.db.Exec(`UPDATE login_boost_state SET available='false', end_time=$1 WHERE char_id=$2 AND week_req=$3`, uint32(t.Unix()), s.charID, pkt.BoostWeekUsed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
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, TimeWeekNext(), s.charID, pkt.BoostWeekUsed)
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
@@ -12,22 +12,25 @@ import (
|
||||
|
||||
func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfSaveMezfesData)
|
||||
s.server.db.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) {
|
||||
pkt := p.(*mhfpacket.MsgMhfLoadMezfesData)
|
||||
|
||||
resp := byteframe.NewByteFrame()
|
||||
resp.WriteUint32(0) // Unk
|
||||
|
||||
resp.WriteUint8(2) // Count of the next 2 uint32s
|
||||
resp.WriteUint32(0)
|
||||
resp.WriteUint32(0)
|
||||
|
||||
resp.WriteUint32(0) // Unk
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
var data []byte
|
||||
s.server.db.QueryRow(`SELECT mezfes FROM characters WHERE id=$1`, s.charID).Scan(&data)
|
||||
bf := byteframe.NewByteFrame()
|
||||
if len(data) > 0 {
|
||||
bf.WriteBytes(data)
|
||||
} else {
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint8(2)
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint32(0)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
||||
@@ -38,7 +41,7 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
||||
// Unk
|
||||
// Start?
|
||||
// End?
|
||||
midnight := Time_Current_Midnight()
|
||||
midnight := TimeMidnight()
|
||||
switch state {
|
||||
case 1:
|
||||
bf.WriteUint32(uint32(midnight.Unix()))
|
||||
@@ -57,13 +60,13 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint32(uint32(midnight.Add(7 * 24 * time.Hour).Unix()))
|
||||
default:
|
||||
bf.WriteBytes(make([]byte, 16))
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // TS Current Time
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix())) // TS Current Time
|
||||
bf.WriteUint8(3)
|
||||
bf.WriteBytes(make([]byte, 4))
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
return
|
||||
}
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // TS Current Time
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix())) // TS Current Time
|
||||
bf.WriteUint8(3)
|
||||
ps.Uint8(bf, "", false)
|
||||
bf.WriteUint16(0) // numEvents
|
||||
@@ -98,7 +101,7 @@ func cleanupFesta(s *Session) {
|
||||
|
||||
func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
||||
timestamps := make([]uint32, 5)
|
||||
midnight := Time_Current_Midnight()
|
||||
midnight := TimeMidnight()
|
||||
if debug && start <= 3 {
|
||||
midnight := uint32(midnight.Unix())
|
||||
switch start {
|
||||
@@ -123,7 +126,7 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
||||
}
|
||||
return timestamps
|
||||
}
|
||||
if start == 0 || Time_Current_Adjusted().Unix() > int64(start)+2977200 {
|
||||
if start == 0 || TimeAdjusted().Unix() > int64(start)+2977200 {
|
||||
cleanupFesta(s)
|
||||
// Generate a new festa, starting midnight tomorrow
|
||||
start = uint32(midnight.Add(24 * time.Hour).Unix())
|
||||
@@ -167,7 +170,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
||||
timestamps = generateFestaTimestamps(s, start, false)
|
||||
}
|
||||
|
||||
if timestamps[0] > uint32(Time_Current_Adjusted().Unix()) {
|
||||
if timestamps[0] > uint32(TimeAdjusted().Unix()) {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
@@ -180,7 +183,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
||||
for _, timestamp := range timestamps {
|
||||
bf.WriteUint32(timestamp)
|
||||
}
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
bf.WriteUint8(4)
|
||||
ps.Uint8(bf, "", false)
|
||||
bf.WriteUint32(0)
|
||||
|
||||
@@ -1724,57 +1724,59 @@ func handleMsgMhfCancelGuildMissionTarget(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
|
||||
type GuildMeal struct {
|
||||
ID uint32 `db:"id"`
|
||||
MealID uint32 `db:"meal_id"`
|
||||
Level uint32 `db:"level"`
|
||||
Expires uint32 `db:"expires"`
|
||||
ID uint32 `db:"id"`
|
||||
MealID uint32 `db:"meal_id"`
|
||||
Level uint32 `db:"level"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfLoadGuildCooking)
|
||||
|
||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||
data, err := s.server.db.Queryx("SELECT id, meal_id, level, expires FROM guild_meals WHERE guild_id = $1", guild.ID)
|
||||
data, err := s.server.db.Queryx("SELECT id, meal_id, level, created_at FROM guild_meals WHERE guild_id = $1", guild.ID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get guild meals from db", zap.Error(err))
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
||||
return
|
||||
}
|
||||
temp := byteframe.NewByteFrame()
|
||||
count := 0
|
||||
var meals []GuildMeal
|
||||
var temp GuildMeal
|
||||
for data.Next() {
|
||||
mealData := &GuildMeal{}
|
||||
err = data.StructScan(&mealData)
|
||||
err = data.StructScan(&temp)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if mealData.Expires > uint32(Time_Current_Adjusted().Add(-60*time.Minute).Unix()) {
|
||||
count++
|
||||
temp.WriteUint32(mealData.ID)
|
||||
temp.WriteUint32(mealData.MealID)
|
||||
temp.WriteUint32(mealData.Level)
|
||||
temp.WriteUint32(mealData.Expires)
|
||||
if temp.CreatedAt.Add(60 * time.Minute).After(TimeAdjusted()) {
|
||||
meals = append(meals, temp)
|
||||
}
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(uint16(count))
|
||||
bf.WriteBytes(temp.Data())
|
||||
bf.WriteUint16(uint16(len(meals)))
|
||||
for _, meal := range meals {
|
||||
bf.WriteUint32(meal.ID)
|
||||
bf.WriteUint32(meal.MealID)
|
||||
bf.WriteUint32(meal.Level)
|
||||
bf.WriteUint32(uint32(meal.CreatedAt.Unix()))
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildCooking)
|
||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||
currentTime := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.GuildMealDuration-60) * time.Minute)
|
||||
if pkt.OverwriteID != 0 {
|
||||
_, err := s.server.db.Exec("DELETE FROM guild_meals WHERE id = $1", pkt.OverwriteID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to delete meal in db", zap.Error(err))
|
||||
}
|
||||
s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, currentTime, pkt.OverwriteID)
|
||||
} else {
|
||||
s.server.db.QueryRow("INSERT INTO guild_meals (guild_id, meal_id, level, created_at) VALUES ($1, $2, $3, $4) RETURNING id", guild.ID, pkt.MealID, pkt.Success, currentTime).Scan(&pkt.OverwriteID)
|
||||
}
|
||||
_, err := s.server.db.Exec("INSERT INTO guild_meals (guild_id, meal_id, level, expires) VALUES ($1, $2, $3, $4)", guild.ID, pkt.MealID, pkt.Success, Time_Current_Adjusted().Add(30*time.Minute).Unix())
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to register meal in db", zap.Error(err))
|
||||
}
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x00})
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(1)
|
||||
bf.WriteUint32(pkt.OverwriteID)
|
||||
bf.WriteUint32(uint32(pkt.MealID))
|
||||
bf.WriteUint32(uint32(pkt.Success))
|
||||
bf.WriteUint32(uint32(currentTime.Unix()))
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) {
|
||||
@@ -1832,7 +1834,7 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
s.server.db.Exec("UPDATE characters SET guild_post_checked = $1 WHERE id = $2", time.Now(), s.charID)
|
||||
s.server.db.Exec("UPDATE characters SET guild_post_checked = now() WHERE id = $1", s.charID)
|
||||
bf := byteframe.NewByteFrame()
|
||||
var postCount uint32
|
||||
for msgs.Next() {
|
||||
@@ -1861,13 +1863,13 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfUpdateGuildMessageBoard)
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt.Request)
|
||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||
if guild == nil {
|
||||
if pkt.MessageOp == 5 {
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||
applicant := false
|
||||
if guild != nil {
|
||||
applicant, _ = guild.HasApplicationForCharID(s, s.charID)
|
||||
}
|
||||
if err != nil || guild == nil || applicant {
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
switch pkt.MessageOp {
|
||||
|
||||
@@ -52,7 +52,7 @@ func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventure)
|
||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, Time_Current_Adjusted().Unix(), Time_Current_Adjusted().Add(6*time.Hour).Unix())
|
||||
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, TimeAdjusted().Unix(), TimeAdjusted().Add(6*time.Hour).Unix())
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func handleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva)
|
||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||
_, 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, Time_Current_Adjusted().Unix(), Time_Current_Adjusted().Add(1*time.Hour).Unix())
|
||||
_, 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, TimeAdjusted().Unix(), TimeAdjusted().Add(1*time.Hour).Unix())
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ SELECT
|
||||
g.id as guild_id,
|
||||
joined_at,
|
||||
coalesce(souls, 0) as souls,
|
||||
rp_today,
|
||||
rp_yesterday,
|
||||
COALESCE(rp_today, 0) AS rp_today,
|
||||
COALESCE(rp_yesterday, 0) AS rp_yesterday,
|
||||
c.name,
|
||||
character.character_id,
|
||||
coalesce(gc.order_index, 0) as order_index,
|
||||
|
||||
@@ -27,7 +27,7 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
hunts := 0
|
||||
rows, _ := s.server.db.Queryx("SELECT id, host_id, destination, level, return, acquired, claimed, hunters, treasure, hunt_data FROM guild_hunts WHERE guild_id=$1 AND $2 < return+604800", guild.ID, Time_Current_Adjusted().Unix())
|
||||
rows, _ := s.server.db.Queryx("SELECT id, host_id, destination, level, return, acquired, claimed, hunters, treasure, hunt_data FROM guild_hunts WHERE guild_id=$1 AND $2 < return+604800", guild.ID, TimeAdjusted().Unix())
|
||||
for rows.Next() {
|
||||
hunt := &TreasureHunt{}
|
||||
err = rows.StructScan(&hunt)
|
||||
@@ -101,7 +101,7 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
}
|
||||
_, err = s.server.db.Exec("INSERT INTO guild_hunts (guild_id, host_id, destination, level, return, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
guild.ID, s.charID, destination, level, Time_Current_Adjusted().Unix(), huntData.Data(), catsUsed)
|
||||
guild.ID, s.charID, destination, level, TimeAdjusted().Unix(), huntData.Data(), catsUsed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {
|
||||
Unk uint32
|
||||
Timestamp uint32
|
||||
}{
|
||||
{0, uint32(Time_Current_Midnight().Add(-12 * time.Hour).Unix())},
|
||||
{0, uint32(Time_Current_Midnight().Add(12 * time.Hour).Unix())},
|
||||
{0, uint32(Time_Current_Midnight().Add(36 * time.Hour).Unix())},
|
||||
{0, uint32(TimeMidnight().Add(-12 * time.Hour).Unix())},
|
||||
{0, uint32(TimeMidnight().Add(12 * time.Hour).Unix())},
|
||||
{0, uint32(TimeMidnight().Add(36 * time.Hour).Unix())},
|
||||
}
|
||||
bf.WriteUint8(uint8(len(legendDispatch)))
|
||||
for _, dispatch := range legendDispatch {
|
||||
@@ -164,8 +164,8 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint32(pactID)
|
||||
bf.WriteUint32(cid)
|
||||
bf.WriteBool(false) // ?
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||
} else {
|
||||
bf.WriteUint8(0)
|
||||
@@ -180,8 +180,8 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
||||
rows.Scan(&name, &cid, &pactID)
|
||||
temp.WriteUint32(pactID)
|
||||
temp.WriteUint32(cid)
|
||||
temp.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||
temp.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||
}
|
||||
bf.WriteUint8(loans)
|
||||
@@ -346,7 +346,7 @@ func getGuildAirouList(s *Session) []CatDefinition {
|
||||
FROM guild_hunts gh
|
||||
INNER JOIN characters c
|
||||
ON gh.host_id = c.id
|
||||
WHERE c.id=$1 AND gh.return+$2>$3`, s.charID, tempBanDuration, Time_Current_Adjusted().Unix())
|
||||
WHERE c.id=$1 AND gh.return+$2>$3`, s.charID, tempBanDuration, TimeAdjusted().Unix())
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to get recently used airous", zap.Error(err))
|
||||
}
|
||||
|
||||
@@ -36,8 +36,9 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
|
||||
resp.WriteUint32(*ref)
|
||||
}
|
||||
} else {
|
||||
resp.WriteUint32(*ref + data*damageMultiplier)
|
||||
*ref += data * damageMultiplier
|
||||
data = uint32(float64(data) * damageMultiplier)
|
||||
resp.WriteUint32(*ref + data)
|
||||
*ref += data
|
||||
}
|
||||
case 13:
|
||||
fallthrough
|
||||
|
||||
@@ -521,7 +521,7 @@ func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(step)
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@ func destructEmptyStages(s *Session) {
|
||||
|
||||
func removeSessionFromStage(s *Session) {
|
||||
// Remove client from old stage.
|
||||
s.stage.Lock()
|
||||
delete(s.stage.clients, s)
|
||||
|
||||
// Delete old stage objects owned by the client.
|
||||
@@ -146,7 +145,6 @@ func removeSessionFromStage(s *Session) {
|
||||
delete(s.stage.objects, object.ownerCharID)
|
||||
}
|
||||
}
|
||||
s.stage.Unlock()
|
||||
destructEmptyStages(s)
|
||||
destructEmptySemaphores(s)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
switch pkt.Unk0 {
|
||||
case 0:
|
||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
bf.WriteUint32(0) // Tied to schedule ID?
|
||||
case 1:
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ type Server struct {
|
||||
sync.Mutex
|
||||
Channels []*Server
|
||||
ID uint16
|
||||
GlobalID string
|
||||
IP string
|
||||
Port uint16
|
||||
logger *zap.Logger
|
||||
@@ -124,19 +125,19 @@ func NewRaviente() *Raviente {
|
||||
return raviente
|
||||
}
|
||||
|
||||
func (r *Raviente) GetRaviMultiplier(s *Server) uint32 {
|
||||
func (r *Raviente) GetRaviMultiplier(s *Server) float64 {
|
||||
raviSema := getRaviSemaphore(s)
|
||||
if raviSema != nil {
|
||||
var minPlayers uint32
|
||||
var minPlayers int
|
||||
if r.register.maxPlayers > 8 {
|
||||
minPlayers = 24
|
||||
} else {
|
||||
minPlayers = 4
|
||||
}
|
||||
if uint32(len(raviSema.clients)) > minPlayers {
|
||||
if len(raviSema.clients) > minPlayers {
|
||||
return 1
|
||||
}
|
||||
return minPlayers / uint32(len(raviSema.clients))
|
||||
return float64(minPlayers / len(raviSema.clients))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -269,6 +270,8 @@ func (s *Server) manageSessions() {
|
||||
// BroadcastMHF queues a MHFPacket to be sent to all sessions.
|
||||
func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
|
||||
// Broadcast the data.
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for _, session := range s.sessions {
|
||||
if session == ignoredSession {
|
||||
continue
|
||||
@@ -291,16 +294,7 @@ func (s *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session,
|
||||
if c == ignoredChannel {
|
||||
continue
|
||||
}
|
||||
for _, session := range c.sessions {
|
||||
if session == ignoredSession {
|
||||
continue
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(uint16(pkt.Opcode()))
|
||||
pkt.Build(bf, session.clientContext)
|
||||
bf.WriteUint16(0x0010)
|
||||
session.QueueSendNonBlocking(bf.Data())
|
||||
}
|
||||
c.BroadcastMHF(pkt, ignoredSession)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ func getLangStrings(s *Server) map[string]string {
|
||||
strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません"
|
||||
strings["commandRaviStartSuccess"] = "大討伐を開始します"
|
||||
strings["commandRaviStartError"] = "大討伐は既に開催されています"
|
||||
strings["commandRaviMultiplier"] = "ラヴィダメージ倍率:x%d"
|
||||
strings["commandRaviMultiplier"] = "ラヴィダメージ倍率:x%.2f"
|
||||
strings["commandRaviResSuccess"] = "復活支援を実行します"
|
||||
strings["commandRaviResError"] = "復活支援は実行されませんでした"
|
||||
strings["commandRaviSedSuccess"] = "鎮静支援を実行します"
|
||||
@@ -146,7 +146,7 @@ func getLangStrings(s *Server) map[string]string {
|
||||
strings["commandRaviNoCommand"] = "No Raviente command specified!"
|
||||
strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment"
|
||||
strings["commandRaviStartError"] = "The Great Slaying has already begun!"
|
||||
strings["commandRaviMultiplier"] = "Raviente multiplier is currently %dx"
|
||||
strings["commandRaviMultiplier"] = "Raviente multiplier is currently %.2fx"
|
||||
strings["commandRaviResSuccess"] = "Sending resurrection support!"
|
||||
strings["commandRaviResError"] = "Resurrection support has not been requested!"
|
||||
strings["commandRaviSedSuccess"] = "Sending sedation support if requested!"
|
||||
|
||||
@@ -73,7 +73,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
|
||||
cryptConn: network.NewCryptConn(conn),
|
||||
sendPackets: make(chan packet, 20),
|
||||
clientContext: &clientctx.ClientContext{}, // Unused
|
||||
sessionStart: Time_Current_Adjusted().Unix(),
|
||||
sessionStart: TimeAdjusted().Unix(),
|
||||
stageMoveStack: stringstack.New(),
|
||||
}
|
||||
return s
|
||||
@@ -82,7 +82,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
|
||||
// Start starts the session packet send and recv loop(s).
|
||||
func (s *Session) Start() {
|
||||
go func() {
|
||||
s.logger.Info("Channel server got 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,
|
||||
// the client DOES NOT initalize the channel connection with 8 NULL bytes.
|
||||
go s.sendLoop()
|
||||
|
||||
@@ -69,7 +69,8 @@ func NewStage(ID string) *Stage {
|
||||
|
||||
// BroadcastMHF queues a MHFPacket to be sent to all sessions in the stage.
|
||||
func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
|
||||
// Broadcast the data.
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for session := range s.clients {
|
||||
if session == ignoredSession {
|
||||
continue
|
||||
|
||||
25
server/channelserver/sys_time.go
Normal file
25
server/channelserver/sys_time.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TimeAdjusted() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone("UTC+9", 9*60*60))
|
||||
return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), baseTime.Hour(), baseTime.Minute(), baseTime.Second(), baseTime.Nanosecond(), baseTime.Location())
|
||||
}
|
||||
|
||||
func TimeMidnight() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone("UTC+9", 9*60*60))
|
||||
return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), 0, 0, 0, 0, baseTime.Location())
|
||||
}
|
||||
|
||||
func TimeWeekStart() time.Time {
|
||||
midnight := TimeMidnight()
|
||||
offset := (int(midnight.Weekday()) - 1) * -24
|
||||
return midnight.Add(time.Hour * time.Duration(offset))
|
||||
}
|
||||
|
||||
func TimeWeekNext() time.Time {
|
||||
return TimeWeekStart().Add(time.Hour * 24 * 7)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
Offset = 9
|
||||
YearAdjust = -7
|
||||
MonthAdjust = 0
|
||||
DayAdjust = 0
|
||||
)
|
||||
|
||||
var (
|
||||
TimeStatic = time.Time{}
|
||||
)
|
||||
|
||||
func Time_Current() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone(fmt.Sprintf("UTC+%d", Offset), Offset*60*60))
|
||||
return baseTime
|
||||
}
|
||||
|
||||
func Time_Current_Adjusted() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone(fmt.Sprintf("UTC+%d", Offset), Offset*60*60)).AddDate(YearAdjust, MonthAdjust, DayAdjust)
|
||||
return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), baseTime.Hour(), baseTime.Minute(), baseTime.Second(), baseTime.Nanosecond(), baseTime.Location())
|
||||
}
|
||||
|
||||
func Time_Current_Midnight() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone(fmt.Sprintf("UTC+%d", Offset), Offset*60*60)).AddDate(YearAdjust, MonthAdjust, DayAdjust)
|
||||
return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), 0, 0, 0, 0, baseTime.Location())
|
||||
}
|
||||
|
||||
func TimeWeekStart() time.Time {
|
||||
midnight := Time_Current_Midnight()
|
||||
offset := (int(midnight.Weekday()) - 1) * -24
|
||||
return midnight.Add(time.Hour * time.Duration(offset))
|
||||
}
|
||||
|
||||
func TimeWeekNext() time.Time {
|
||||
return TimeWeekStart().Add(time.Hour * 24 * 7)
|
||||
}
|
||||
|
||||
func Time_Current_Week_uint8() uint8 {
|
||||
baseTime := time.Now().In(time.FixedZone(fmt.Sprintf("UTC+%d", Offset), Offset*60*60)).AddDate(YearAdjust, MonthAdjust, DayAdjust)
|
||||
|
||||
_, thisWeek := baseTime.ISOWeek()
|
||||
_, beginningOfTheMonth := time.Date(baseTime.Year(), baseTime.Month(), 1, 0, 0, 0, 0, baseTime.Location()).ISOWeek()
|
||||
|
||||
return uint8(1 + thisWeek - beginningOfTheMonth)
|
||||
}
|
||||
|
||||
func Time_static() time.Time {
|
||||
if TimeStatic.IsZero() {
|
||||
TimeStatic = Time_Current_Adjusted()
|
||||
}
|
||||
return TimeStatic
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func (s *Server) Start() error {
|
||||
|
||||
// Shutdown exits the server gracefully.
|
||||
func (s *Server) Shutdown() {
|
||||
s.logger.Debug("Shutting down")
|
||||
s.logger.Debug("Shutting down...")
|
||||
|
||||
s.Lock()
|
||||
s.isShuttingDown = true
|
||||
@@ -111,7 +111,9 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Debug("Got entrance server command:\n", zap.String("raw", hex.Dump(pkt)))
|
||||
if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.LogInboundMessages {
|
||||
fmt.Printf("[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt))
|
||||
}
|
||||
|
||||
local := false
|
||||
if strings.Split(conn.RemoteAddr().String(), ":")[0] == "127.0.0.1" {
|
||||
|
||||
@@ -2,6 +2,8 @@ package entranceserver
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"erupe-ce/common/stringsupport"
|
||||
@@ -66,7 +68,7 @@ func encodeServerInfo(config *config.Config, s *Server, local bool) []byte {
|
||||
bf.WriteUint16(0x3039)
|
||||
}
|
||||
}
|
||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Unix()))
|
||||
bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix()))
|
||||
bf.WriteUint32(0x0000003C)
|
||||
return bf.Data()
|
||||
}
|
||||
@@ -92,6 +94,11 @@ func makeHeader(data []byte, respType string, entryCount uint16, key byte) []byt
|
||||
func makeSv2Resp(config *config.Config, s *Server, local bool) []byte {
|
||||
serverInfos := config.Entrance.Entries
|
||||
rawServerData := encodeServerInfo(config, s, local)
|
||||
|
||||
if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.LogOutboundMessages {
|
||||
fmt.Printf("[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(rawServerData), hex.Dump(rawServerData))
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(makeHeader(rawServerData, "SV2", uint16(len(serverInfos)), 0x00))
|
||||
return bf.Data()
|
||||
@@ -109,11 +116,15 @@ func makeUsrResp(pkt []byte, s *Server) []byte {
|
||||
err := s.db.QueryRow("SELECT(SELECT server_id FROM sign_sessions WHERE char_id=$1) AS _", cid).Scan(&sid)
|
||||
if err != nil {
|
||||
resp.WriteBytes(make([]byte, 4))
|
||||
continue
|
||||
} else {
|
||||
resp.WriteUint16(sid)
|
||||
resp.WriteUint16(0)
|
||||
}
|
||||
}
|
||||
|
||||
if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.LogOutboundMessages {
|
||||
fmt.Printf("[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(resp.Data()), hex.Dump(resp.Data()))
|
||||
}
|
||||
|
||||
return makeHeader(resp.Data(), "USR", userEntries, 0x00)
|
||||
}
|
||||
|
||||
@@ -111,9 +111,10 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
||||
if s.server.erupeConfig.HideLoginNotice {
|
||||
bf.WriteUint8(0)
|
||||
} else {
|
||||
bf.WriteUint8(1) // Notice count
|
||||
noticeText := s.server.erupeConfig.LoginNotice
|
||||
ps.Uint32(bf, noticeText, true)
|
||||
bf.WriteUint8(uint8(len(s.server.erupeConfig.LoginNotices)))
|
||||
for _, notice := range s.server.erupeConfig.LoginNotices {
|
||||
ps.Uint32(bf, notice, true)
|
||||
}
|
||||
}
|
||||
|
||||
bf.WriteUint32(s.server.getLastCID(uid))
|
||||
@@ -127,12 +128,7 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
||||
bf.WriteUint16(0x0001)
|
||||
bf.WriteUint16(0x4E20)
|
||||
ps.Uint16(bf, "", false) // unk ipv4
|
||||
if returnExpiry.Before(time.Now()) {
|
||||
// Hack to make Return work while having a non-adjusted expiry
|
||||
bf.WriteUint32(0)
|
||||
} else {
|
||||
bf.WriteUint32(uint32(returnExpiry.Unix()))
|
||||
}
|
||||
bf.WriteUint32(uint32(returnExpiry.Unix()))
|
||||
bf.WriteUint32(0x00000000)
|
||||
bf.WriteUint32(0x0A5197DF) // unk id
|
||||
|
||||
@@ -140,9 +136,9 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
||||
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt
|
||||
if mezfes {
|
||||
// Start time
|
||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
|
||||
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
|
||||
// End time
|
||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Add(24 * time.Hour * 7).Unix()))
|
||||
bf.WriteUint32(uint32(channelserver.TimeWeekNext().Unix()))
|
||||
bf.WriteUint8(2) // Unk
|
||||
bf.WriteUint32(20) // Single tickets
|
||||
bf.WriteUint32(10) // Group tickets
|
||||
|
||||
@@ -3,6 +3,7 @@ package signserver
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
@@ -23,6 +24,11 @@ type Session struct {
|
||||
|
||||
func (s *Session) work() {
|
||||
pkt, err := s.cryptConn.ReadPacket()
|
||||
|
||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogInboundMessages {
|
||||
fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -33,8 +39,6 @@ func (s *Session) work() {
|
||||
}
|
||||
|
||||
func (s *Session) handlePacket(pkt []byte) error {
|
||||
sugar := s.logger.Sugar()
|
||||
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt)
|
||||
reqType := string(bf.ReadNullTerminatedBytes())
|
||||
switch reqType {
|
||||
@@ -50,13 +54,16 @@ func (s *Session) handlePacket(pkt []byte) error {
|
||||
characterID := int(bf.ReadUint32())
|
||||
_ = int(bf.ReadUint32()) // login_token_number
|
||||
s.server.deleteCharacter(characterID, loginTokenString)
|
||||
sugar.Infof("Deleted character ID: %v\n", characterID)
|
||||
s.logger.Info("Deleted character", zap.Int("CharacterID", characterID))
|
||||
err := s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
sugar.Infof("Got unknown request type %s, data:\n%s\n", reqType, hex.Dump(bf.DataFromCurrent()))
|
||||
s.logger.Warn("Unknown sign request", zap.String("reqType", reqType))
|
||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogInboundMessages {
|
||||
fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -66,14 +73,7 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
|
||||
reqUsername := string(bf.ReadNullTerminatedBytes())
|
||||
reqPassword := string(bf.ReadNullTerminatedBytes())
|
||||
reqSkey := string(bf.ReadNullTerminatedBytes())
|
||||
|
||||
s.server.logger.Info(
|
||||
"Got sign in request",
|
||||
zap.String("reqUsername", reqUsername),
|
||||
zap.String("reqPassword", reqPassword),
|
||||
zap.String("reqSkey", reqSkey),
|
||||
)
|
||||
_ = string(bf.ReadNullTerminatedBytes()) // Unk
|
||||
|
||||
newCharaReq := false
|
||||
|
||||
@@ -90,14 +90,14 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
var serverRespBytes []byte
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
s.logger.Info("Account not found", zap.String("reqUsername", reqUsername))
|
||||
s.logger.Info("User not found", zap.String("Username", reqUsername))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EAUTH)
|
||||
|
||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.AutoCreateAccount {
|
||||
s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword))
|
||||
s.logger.Info("Creating user", zap.String("Username", reqUsername))
|
||||
err = s.server.registerDBAccount(reqUsername, reqPassword)
|
||||
if err != nil {
|
||||
s.logger.Info("Error on creating new account", zap.Error(err))
|
||||
s.logger.Error("Error registering new user", zap.Error(err))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
var id int
|
||||
err = s.server.db.QueryRow("SELECT id FROM users WHERE username = $1", reqUsername).Scan(&id)
|
||||
if err != nil {
|
||||
s.logger.Info("Error on querying account id", zap.Error(err))
|
||||
s.logger.Error("Error getting new user ID", zap.Error(err))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
@@ -117,15 +117,15 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
break
|
||||
case err != nil:
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
s.logger.Warn("Got error on SQL query", zap.Error(err))
|
||||
s.logger.Error("Error getting user details", zap.Error(err))
|
||||
break
|
||||
default:
|
||||
if bcrypt.CompareHashAndPassword([]byte(password), []byte(reqPassword)) == nil {
|
||||
s.logger.Info("Passwords match!")
|
||||
s.logger.Debug("Passwords match!")
|
||||
if newCharaReq {
|
||||
err = s.server.newUserChara(reqUsername)
|
||||
if err != nil {
|
||||
s.logger.Info("Error on adding new character to account", zap.Error(err))
|
||||
s.logger.Error("Error adding new character to user", zap.Error(err))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
@@ -139,12 +139,16 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
// }
|
||||
serverRespBytes = s.makeSignInResp(id)
|
||||
} else {
|
||||
s.logger.Info("Passwords don't match!")
|
||||
s.logger.Warn("Incorrect password")
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EPASS)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogOutboundMessages {
|
||||
fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(serverRespBytes), hex.Dump(serverRespBytes))
|
||||
}
|
||||
|
||||
err = s.cryptConn.SendPacket(serverRespBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -55,7 +55,7 @@ func (s *Server) Start() error {
|
||||
|
||||
// Shutdown exits the server gracefully.
|
||||
func (s *Server) Shutdown() {
|
||||
s.logger.Debug("Shutting down")
|
||||
s.logger.Debug("Shutting down...")
|
||||
|
||||
s.Lock()
|
||||
s.isShuttingDown = true
|
||||
@@ -86,14 +86,14 @@ func (s *Server) acceptClients() {
|
||||
}
|
||||
|
||||
func (s *Server) handleConnection(conn net.Conn) {
|
||||
s.logger.Info("Got connection to sign server", zap.String("remoteaddr", conn.RemoteAddr().String()))
|
||||
s.logger.Debug("New connection", zap.String("RemoteAddr", conn.RemoteAddr().String()))
|
||||
defer conn.Close()
|
||||
|
||||
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
|
||||
nullInit := make([]byte, 8)
|
||||
_, err := io.ReadFull(conn, nullInit)
|
||||
if err != nil {
|
||||
s.logger.Error("Error initialising sign server connection", zap.Error(err))
|
||||
s.logger.Error("Error initializing connection", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user