mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-29 20:12:31 +02:00
Merge branch 'main' into fix/stage-concurrent-map
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -73,6 +73,7 @@
|
|||||||
{"Name": "HunterSupport", "Enabled": false},
|
{"Name": "HunterSupport", "Enabled": false},
|
||||||
{"Name": "NBoost", "Enabled": false},
|
{"Name": "NBoost", "Enabled": false},
|
||||||
{"Name": "NetCafe", "Enabled": true},
|
{"Name": "NetCafe", "Enabled": true},
|
||||||
|
{"Name": "OfficialCafe", "Enabled": true},
|
||||||
{"Name": "HLRenewing", "Enabled": true},
|
{"Name": "HLRenewing", "Enabled": true},
|
||||||
{"Name": "EXRenewing", "Enabled": true}
|
{"Name": "EXRenewing", "Enabled": true}
|
||||||
],
|
],
|
||||||
|
|||||||
6
go.mod
6
go.mod
@@ -8,18 +8,16 @@ require (
|
|||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/jmoiron/sqlx v1.3.4
|
github.com/jmoiron/sqlx v1.3.4
|
||||||
github.com/lib/pq v1.10.4
|
github.com/lib/pq v1.10.4
|
||||||
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96
|
|
||||||
github.com/spf13/viper v1.8.1
|
github.com/spf13/viper v1.8.1
|
||||||
go.uber.org/zap v1.18.1
|
go.uber.org/zap v1.18.1
|
||||||
golang.org/x/crypto v0.1.0
|
golang.org/x/crypto v0.1.0
|
||||||
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
|
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
|
||||||
golang.org/x/text v0.4.0
|
golang.org/x/text v0.7.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // 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/gorilla/websocket v1.4.2 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/magiconair/properties v1.8.5 // indirect
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
@@ -32,7 +30,7 @@ require (
|
|||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.7.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/ini.v1 v1.62.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.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.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.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
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.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.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/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/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/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/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/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 h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
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-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-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.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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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/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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/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.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
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-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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/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.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.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
20
main.go
20
main.go
@@ -5,6 +5,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"runtime/debug"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -29,13 +30,24 @@ func cleanDB(db *sqlx.DB) {
|
|||||||
_ = db.MustExec("DELETE FROM users")
|
_ = 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() {
|
func main() {
|
||||||
var err error
|
var err error
|
||||||
zapLogger, _ := zap.NewDevelopment()
|
zapLogger, _ := zap.NewDevelopment()
|
||||||
defer zapLogger.Sync()
|
defer zapLogger.Sync()
|
||||||
logger := zapLogger.Named("main")
|
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 == "" {
|
if config.ErupeConfig.Database.Password == "" {
|
||||||
preventClose("Database password is blank")
|
preventClose("Database password is blank")
|
||||||
@@ -113,6 +125,8 @@ func main() {
|
|||||||
logger.Info("Done cleaning DB")
|
logger.Info("Done cleaning DB")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Info(fmt.Sprintf("Server Time: %s", channelserver.TimeAdjusted().String()))
|
||||||
|
|
||||||
// Now start our server(s).
|
// Now start our server(s).
|
||||||
|
|
||||||
// Entrance server.
|
// Entrance server.
|
||||||
@@ -211,12 +225,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Info("Finished starting Erupe")
|
||||||
|
|
||||||
// Wait for exit or interrupt with ctrl+C.
|
// Wait for exit or interrupt with ctrl+C.
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
logger.Info("Trying to shutdown gracefully")
|
logger.Info("Shutting down...")
|
||||||
|
|
||||||
if config.ErupeConfig.Channel.Enabled {
|
if config.ErupeConfig.Channel.Enabled {
|
||||||
for _, c := range channels {
|
for _, c := range channels {
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetBoxGachaInfo represents the MSG_MHF_GET_BOX_GACHA_INFO
|
// MsgMhfGetBoxGachaInfo represents the MSG_MHF_GET_BOX_GACHA_INFO
|
||||||
type MsgMhfGetBoxGachaInfo struct{
|
type MsgMhfGetBoxGachaInfo struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
GachaHash uint32
|
GachaID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -22,7 +22,7 @@ func (m *MsgMhfGetBoxGachaInfo) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetBoxGachaInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetBoxGachaInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.GachaHash = bf.ReadUint32()
|
m.GachaID = bf.ReadUint32()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetStepupStatus represents the MSG_MHF_GET_STEPUP_STATUS
|
// MsgMhfGetStepupStatus represents the MSG_MHF_GET_STEPUP_STATUS
|
||||||
type MsgMhfGetStepupStatus struct{
|
type MsgMhfGetStepupStatus struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
GachaHash uint32
|
GachaID uint32
|
||||||
Unk uint8
|
Unk uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -23,7 +23,7 @@ func (m *MsgMhfGetStepupStatus) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetStepupStatus) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetStepupStatus) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.GachaHash = bf.ReadUint32()
|
m.GachaID = bf.ReadUint32()
|
||||||
m.Unk = bf.ReadUint8()
|
m.Unk = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfGetWeeklySeibatuRankingReward represents the MSG_MHF_GET_WEEKLY_SEIBATU_RANKING_REWARD
|
// MsgMhfGetWeeklySeibatuRankingReward represents the MSG_MHF_GET_WEEKLY_SEIBATU_RANKING_REWARD
|
||||||
type MsgMhfGetWeeklySeibatuRankingReward struct{}
|
type MsgMhfGetWeeklySeibatuRankingReward struct {
|
||||||
|
AckHandle uint32
|
||||||
|
Unk0 uint32
|
||||||
|
Unk1 uint32
|
||||||
|
Unk2 uint32
|
||||||
|
Unk3 uint32
|
||||||
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfGetWeeklySeibatuRankingReward) Opcode() network.PacketID {
|
func (m *MsgMhfGetWeeklySeibatuRankingReward) Opcode() network.PacketID {
|
||||||
@@ -18,7 +24,12 @@ func (m *MsgMhfGetWeeklySeibatuRankingReward) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfGetWeeklySeibatuRankingReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfGetWeeklySeibatuRankingReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
return errors.New("NOT IMPLEMENTED")
|
m.AckHandle = bf.ReadUint32()
|
||||||
|
m.Unk0 = bf.ReadUint32()
|
||||||
|
m.Unk1 = bf.ReadUint32()
|
||||||
|
m.Unk2 = bf.ReadUint32()
|
||||||
|
m.Unk3 = bf.ReadUint32()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPlayBoxGacha represents the MSG_MHF_PLAY_BOX_GACHA
|
// MsgMhfPlayBoxGacha represents the MSG_MHF_PLAY_BOX_GACHA
|
||||||
type MsgMhfPlayBoxGacha struct{
|
type MsgMhfPlayBoxGacha struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
GachaHash uint32
|
GachaID uint32
|
||||||
RollType uint8
|
RollType uint8
|
||||||
CurrencyMode uint8
|
GachaType uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -24,9 +24,9 @@ func (m *MsgMhfPlayBoxGacha) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPlayBoxGacha) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPlayBoxGacha) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.GachaHash = bf.ReadUint32()
|
m.GachaID = bf.ReadUint32()
|
||||||
m.RollType = bf.ReadUint8()
|
m.RollType = bf.ReadUint8()
|
||||||
m.CurrencyMode = bf.ReadUint8()
|
m.GachaType = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPlayNormalGacha represents the MSG_MHF_PLAY_NORMAL_GACHA
|
// MsgMhfPlayNormalGacha represents the MSG_MHF_PLAY_NORMAL_GACHA
|
||||||
type MsgMhfPlayNormalGacha struct{
|
type MsgMhfPlayNormalGacha struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
GachaHash uint32
|
GachaID uint32
|
||||||
RollType uint8
|
RollType uint8
|
||||||
CurrencyMode uint8
|
GachaType uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -24,9 +24,9 @@ func (m *MsgMhfPlayNormalGacha) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPlayNormalGacha) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPlayNormalGacha) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.GachaHash = bf.ReadUint32()
|
m.GachaID = bf.ReadUint32()
|
||||||
m.RollType = bf.ReadUint8()
|
m.RollType = bf.ReadUint8()
|
||||||
m.CurrencyMode = bf.ReadUint8()
|
m.GachaType = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPlayStepupGacha represents the MSG_MHF_PLAY_STEPUP_GACHA
|
// MsgMhfPlayStepupGacha represents the MSG_MHF_PLAY_STEPUP_GACHA
|
||||||
type MsgMhfPlayStepupGacha struct{
|
type MsgMhfPlayStepupGacha struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
GachaHash uint32
|
GachaID uint32
|
||||||
RollType uint8
|
RollType uint8
|
||||||
CurrencyMode uint8
|
GachaType uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -24,9 +24,9 @@ func (m *MsgMhfPlayStepupGacha) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPlayStepupGacha) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPlayStepupGacha) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.GachaHash = bf.ReadUint32()
|
m.GachaID = bf.ReadUint32()
|
||||||
m.RollType = bf.ReadUint8()
|
m.RollType = bf.ReadUint8()
|
||||||
m.CurrencyMode = bf.ReadUint8()
|
m.GachaType = bf.ReadUint8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN
|
// MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN
|
||||||
type MsgMhfPostTinyBin struct{}
|
type MsgMhfPostTinyBin struct {
|
||||||
|
AckHandle uint32
|
||||||
|
Unk []byte
|
||||||
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfPostTinyBin) Opcode() network.PacketID {
|
func (m *MsgMhfPostTinyBin) Opcode() network.PacketID {
|
||||||
@@ -18,7 +21,9 @@ func (m *MsgMhfPostTinyBin) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
return errors.New("NOT IMPLEMENTED")
|
m.AckHandle = bf.ReadUint32()
|
||||||
|
m.Unk = bf.ReadBytes(14)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -1,15 +1,26 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfPresentBox represents the MSG_MHF_PRESENT_BOX
|
// MsgMhfPresentBox represents the MSG_MHF_PRESENT_BOX
|
||||||
type MsgMhfPresentBox struct{}
|
type MsgMhfPresentBox struct {
|
||||||
|
AckHandle uint32
|
||||||
|
Unk0 uint32
|
||||||
|
Unk1 uint32
|
||||||
|
Unk2 uint32
|
||||||
|
Unk3 uint32
|
||||||
|
Unk4 uint32
|
||||||
|
Unk5 uint32
|
||||||
|
Unk6 uint32
|
||||||
|
Unk7 uint32
|
||||||
|
Unk8 uint32
|
||||||
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfPresentBox) Opcode() network.PacketID {
|
func (m *MsgMhfPresentBox) Opcode() network.PacketID {
|
||||||
@@ -18,7 +29,17 @@ func (m *MsgMhfPresentBox) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfPresentBox) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfPresentBox) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
return errors.New("NOT IMPLEMENTED")
|
m.AckHandle = bf.ReadUint32()
|
||||||
|
m.Unk0 = bf.ReadUint32()
|
||||||
|
m.Unk1 = bf.ReadUint32()
|
||||||
|
m.Unk2 = bf.ReadUint32()
|
||||||
|
m.Unk3 = bf.ReadUint32()
|
||||||
|
m.Unk4 = bf.ReadUint32()
|
||||||
|
m.Unk5 = bf.ReadUint32()
|
||||||
|
m.Unk6 = bf.ReadUint32()
|
||||||
|
m.Unk7 = bf.ReadUint32()
|
||||||
|
m.Unk8 = bf.ReadUint32()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfReceiveGachaItem represents the MSG_MHF_RECEIVE_GACHA_ITEM
|
// MsgMhfReceiveGachaItem represents the MSG_MHF_RECEIVE_GACHA_ITEM
|
||||||
type MsgMhfReceiveGachaItem struct{
|
type MsgMhfReceiveGachaItem struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
Unk0 uint16
|
Max uint8
|
||||||
|
Freeze bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -22,7 +23,8 @@ func (m *MsgMhfReceiveGachaItem) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfReceiveGachaItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfReceiveGachaItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.Unk0 = bf.ReadUint16()
|
m.Max = bf.ReadUint8()
|
||||||
|
m.Freeze = bf.ReadBool()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package mhfpacket
|
package mhfpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"erupe-ce/network/clientctx"
|
|
||||||
"erupe-ce/network"
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
"erupe-ce/network"
|
||||||
|
"erupe-ce/network/clientctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfResetBoxGachaInfo represents the MSG_MHF_RESET_BOX_GACHA_INFO
|
// MsgMhfResetBoxGachaInfo represents the MSG_MHF_RESET_BOX_GACHA_INFO
|
||||||
type MsgMhfResetBoxGachaInfo struct{
|
type MsgMhfResetBoxGachaInfo struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
GachaHash uint32
|
GachaID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
@@ -22,7 +22,7 @@ func (m *MsgMhfResetBoxGachaInfo) Opcode() network.PacketID {
|
|||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfResetBoxGachaInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfResetBoxGachaInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.GachaHash = bf.ReadUint32()
|
m.GachaID = bf.ReadUint32()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,10 @@ func Courses() []Course {
|
|||||||
{Aliases: []string{"Hiden", "Secret"}, ID: 10}, // Secret
|
{Aliases: []string{"Hiden", "Secret"}, ID: 10}, // Secret
|
||||||
{Aliases: []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, ID: 11}, // Royal
|
{Aliases: []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, ID: 11}, // Royal
|
||||||
{Aliases: []string{"NBoost", "NetCafeBoost", "Boost"}, ID: 12},
|
{Aliases: []string{"NBoost", "NetCafeBoost", "Boost"}, ID: 12},
|
||||||
// 13-25 do nothing
|
// 13-19 = (unknown), 20 = DEBUG, 21 = COG_LINK_EXPIRED, 22 = 360_GOLD, 23 = PS3_TROP
|
||||||
{Aliases: []string{"NetCafe", "Cafe", "InternetCafe"}, ID: 26},
|
{Aliases: []string{"COG"}, ID: 24},
|
||||||
|
{Aliases: []string{"NetCafe", "Cafe", "InternetCafe"}, ID: 25},
|
||||||
|
{Aliases: []string{"OfficialCafe", "Official"}, ID: 26},
|
||||||
{Aliases: []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew"}, ID: 27},
|
{Aliases: []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew"}, ID: 27},
|
||||||
{Aliases: []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew"}, ID: 28},
|
{Aliases: []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew"}, ID: 28},
|
||||||
{Aliases: []string{"Free"}, ID: 29},
|
{Aliases: []string{"Free"}, ID: 29},
|
||||||
|
|||||||
77
patch-schema/gacha-db-2.sql
Normal file
77
patch-schema/gacha-db-2.sql
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE characters
|
||||||
|
DROP COLUMN IF EXISTS gacha_prem;
|
||||||
|
|
||||||
|
ALTER TABLE characters
|
||||||
|
DROP COLUMN IF EXISTS gacha_trial;
|
||||||
|
|
||||||
|
ALTER TABLE characters
|
||||||
|
DROP COLUMN IF EXISTS frontier_points;
|
||||||
|
|
||||||
|
ALTER TABLE users
|
||||||
|
ADD IF NOT EXISTS gacha_premium INT;
|
||||||
|
|
||||||
|
ALTER TABLE users
|
||||||
|
ADD IF NOT EXISTS gacha_trial INT;
|
||||||
|
|
||||||
|
ALTER TABLE users
|
||||||
|
ADD IF NOT EXISTS frontier_points INT;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.gacha_shop;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS public.gacha_shop (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
min_gr INTEGER,
|
||||||
|
min_hr INTEGER,
|
||||||
|
name TEXT,
|
||||||
|
url_banner TEXT,
|
||||||
|
url_feature TEXT,
|
||||||
|
url_thumbnail TEXT,
|
||||||
|
wide BOOLEAN,
|
||||||
|
recommended BOOLEAN,
|
||||||
|
gacha_type INTEGER,
|
||||||
|
hidden BOOLEAN
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.gacha_shop_items;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS public.gacha_entries (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
gacha_id INTEGER,
|
||||||
|
entry_type INTEGER,
|
||||||
|
item_type INTEGER,
|
||||||
|
item_number INTEGER,
|
||||||
|
item_quantity INTEGER,
|
||||||
|
weight INTEGER,
|
||||||
|
rarity INTEGER,
|
||||||
|
rolls INTEGER,
|
||||||
|
frontier_points INTEGER,
|
||||||
|
daily_limit INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS public.gacha_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
entry_id INTEGER,
|
||||||
|
item_type INTEGER,
|
||||||
|
item_id INTEGER,
|
||||||
|
quantity INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.stepup_state;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS public.gacha_stepup (
|
||||||
|
gacha_id INTEGER,
|
||||||
|
step INTEGER,
|
||||||
|
character_id INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.lucky_box_state;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS public.gacha_box (
|
||||||
|
gacha_id INTEGER,
|
||||||
|
entry_id INTEGER,
|
||||||
|
character_id INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
END;
|
||||||
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;
|
||||||
17
patch-schema/unused-tables.sql
Normal file
17
patch-schema/unused-tables.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.account_ban;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.account_history;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.account_moderation;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.account_sub;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.history;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.questlists;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS public.schema_migrations;
|
||||||
|
|
||||||
|
END;
|
||||||
@@ -79,7 +79,7 @@ func updateRights(s *Session) {
|
|||||||
rights := []mhfpacket.ClientRight{{1, 0, 0}}
|
rights := []mhfpacket.ClientRight{{1, 0, 0}}
|
||||||
var netcafeBitSet bool
|
var netcafeBitSet bool
|
||||||
for _, course := range s.courses {
|
for _, course := range s.courses {
|
||||||
if (course.ID == 9 || course.ID == 26) && !netcafeBitSet {
|
if (course.ID == 9 || course.ID == 25 || course.ID == 26) && !netcafeBitSet {
|
||||||
netcafeBitSet = true
|
netcafeBitSet = true
|
||||||
rightsInt += 0x40000000 // set netcafe bit
|
rightsInt += 0x40000000 // set netcafe bit
|
||||||
rights = append(rights, mhfpacket.ClientRight{ID: 30})
|
rights = append(rights, mhfpacket.ClientRight{ID: 30})
|
||||||
@@ -144,7 +144,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
updateRights(s)
|
updateRights(s)
|
||||||
bf := byteframe.NewByteFrame()
|
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)
|
_, 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 {
|
if err != nil {
|
||||||
@@ -156,7 +156,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
panic(err)
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ func logoutPlayer(s *Session) {
|
|||||||
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)
|
_ = 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
|
timePlayed += sessionTime
|
||||||
|
|
||||||
var rpGained int
|
var rpGained int
|
||||||
@@ -276,7 +276,7 @@ func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
resp := &mhfpacket.MsgSysTime{
|
resp := &mhfpacket.MsgSysTime{
|
||||||
GetRemoteTime: false,
|
GetRemoteTime: false,
|
||||||
Timestamp: uint32(Time_Current_Adjusted().Unix()), // JP timezone
|
Timestamp: uint32(TimeAdjusted().Unix()), // JP timezone
|
||||||
}
|
}
|
||||||
s.QueueSendMHF(resp)
|
s.QueueSendMHF(resp)
|
||||||
}
|
}
|
||||||
@@ -528,8 +528,6 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {}
|
|
||||||
|
|
||||||
func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -1507,7 +1505,7 @@ func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
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)
|
_ = 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)
|
s.server.db.Exec("UPDATE characters SET bonus_quests = 0, daily_quests = 0 WHERE id=$1", s.charID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1706,14 +1704,6 @@ func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) {}
|
|||||||
|
|
||||||
func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetTinyBin)
|
|
||||||
// requested after conquest quests
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {}
|
|
||||||
|
|
||||||
func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -1723,45 +1713,6 @@ func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetRyoudama)
|
|
||||||
// likely guild related
|
|
||||||
// REQ: 00 04 13 53 8F 18 00
|
|
||||||
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 01 FE 4E
|
|
||||||
// REQ: 00 06 13 53 8F 18 00
|
|
||||||
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00
|
|
||||||
// REQ: 00 05 13 53 8F 18 00
|
|
||||||
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 0E 2A 15 9E CC 00 00 00 01 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 1E 55 B0 2F 00 00 00 01 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 2A 15 9E CC 00 00 00 02 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 03 D5 30 56 00 00 00 02 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 3F 57 76 9F 00 00 00 03 93 56 92 6E 96 B3 97 70 00 00 00 00 00 00 38 D9 0E C4 00 00 00 03 87 64 83 78 83 42 00 00 00 00 00 00 00 00 23 F3 B9 77 00 00 00 04 82 B3 82 CC 82 DC 82 E9 81 99 00 00 00 00 3F 1B 17 9C 00 00 00 04 82 B1 82 A4 82 BD 00 00 00 00 00 00 00 00 00 B9 F9 C0 00 00 00 05 82 CD 82 E9 82 A9 00 00 00 00 00 00 00 00 23 9F 9A EA 00 00 00 05 83 70 83 62 83 4C 83 83 83 49 00 00 00 00 38 D9 0E C4 00 00 00 06 87 64 83 78 83 42 00 00 00 00 00 00 00 00 1E 55 B0 2F 00 00 00 06 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 03 D5 30 56 00 00 00 07 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 02 D3 B8 77 00 00 00 07 6F 77 6C 32 35 32 35 00 00 00 00 00 00 00
|
|
||||||
data, _ := hex.DecodeString("0A218EAD0000000000000000000000010000000000000000")
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {}
|
|
||||||
|
|
||||||
func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
// if the game gets bad responses for this it breaks the ability to save
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetTenrouirai)
|
|
||||||
var data []byte
|
|
||||||
var err error
|
|
||||||
if pkt.Unk0 == 1 {
|
|
||||||
data, err = hex.DecodeString("0A218EAD000000000000000000000001010000000000060010")
|
|
||||||
} else if pkt.Unk2 == 4 {
|
|
||||||
data, err = hex.DecodeString("0A218EAD0000000000000000000000210101005000000202010102020104001000000202010102020106003200000202010002020104000C003202020101020201030032000002020101020202059C4000000202010002020105C35000320202010102020201003C00000202010102020203003200000201010001020203002800320201010101020204000C00000201010101020206002800000201010001020101003C00320201020101020105C35000000301020101020106003200000301020001020104001000320301020101020105C350000003010201010202030028000003010200010201030032003203010201010202059C4000000301020101010206002800000301020001010201003C00320301020101010206003200000301020101010204000C000003010200010101010050003203010201010101059C40000003010201010101030032000003010200010101040010003203010001010101060032000003010001010102030028000003010001010101010050003203010000010102059C4000000301000001010206002800000301000001010010")
|
|
||||||
} else {
|
|
||||||
data = []byte{0x00, 0x00, 0x00, 0x00}
|
|
||||||
s.logger.Info("GET_TENROUIRAI request for unknown type")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfPostTenrouirai)
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|||||||
@@ -37,11 +37,8 @@ func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfCheckDailyCafepoint)
|
pkt := p.(*mhfpacket.MsgMhfCheckDailyCafepoint)
|
||||||
|
|
||||||
// get next midday
|
midday := TimeMidnight().Add(12 * time.Hour)
|
||||||
var t = Time_static()
|
if TimeAdjusted().After(midday) {
|
||||||
year, month, day := t.Date()
|
|
||||||
midday := time.Date(year, month, day, 12, 0, 0, 0, t.Location())
|
|
||||||
if t.After(midday) {
|
|
||||||
midday = midday.Add(24 * time.Hour)
|
midday = midday.Add(24 * time.Hour)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +51,7 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
var bondBonus, bonusQuests, dailyQuests uint32
|
var bondBonus, bonusQuests, dailyQuests uint32
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
if t.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 = 3 // HRP bonus quests?
|
bonusQuests = 3 // HRP bonus quests?
|
||||||
@@ -80,7 +77,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
cafeReset = TimeWeekNext()
|
cafeReset = TimeWeekNext()
|
||||||
s.server.db.Exec(`UPDATE characters SET cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID)
|
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()
|
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(`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)
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
if s.FindCourse("NetCafe").ID != 0 || s.FindCourse("N").ID != 0 {
|
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.WriteUint32(cafeTime) // Total cafe time
|
||||||
bf.WriteUint16(0)
|
bf.WriteUint16(0)
|
||||||
@@ -142,7 +139,7 @@ func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
resp := byteframe.NewByteFrame()
|
resp := byteframe.NewByteFrame()
|
||||||
resp.WriteUint32(0)
|
resp.WriteUint32(0)
|
||||||
resp.WriteUint32(uint32(time.Now().Unix()))
|
resp.WriteUint32(uint32(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())
|
||||||
@@ -165,7 +162,7 @@ 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, Time_Current_Adjusted().Unix()-s.sessionStart)
|
) >= time_req`, s.charID, TimeAdjusted().Unix()-s.sessionStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
} else {
|
} else {
|
||||||
@@ -222,7 +219,7 @@ func addPointNetcafe(s *Session, p int) error {
|
|||||||
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 := Time_Current_Adjusted().Add(100 * time.Minute)
|
boostLimit := TimeAdjusted().Add(120 * time.Minute)
|
||||||
s.server.db.Exec("UPDATE characters SET boost_time=$1 WHERE id=$2", boostLimit, s.charID)
|
s.server.db.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())
|
||||||
@@ -255,7 +252,7 @@ func handleMsgMhfGetBoostRight(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if boostLimit.Unix() > Time_Current_Adjusted().Unix() {
|
if boostLimit.After(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})
|
||||||
|
|||||||
@@ -1,9 +1,36 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfGetRyoudama)
|
||||||
|
// likely guild related
|
||||||
|
// REQ: 00 04 13 53 8F 18 00
|
||||||
|
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 01 FE 4E
|
||||||
|
// REQ: 00 06 13 53 8F 18 00
|
||||||
|
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00
|
||||||
|
// REQ: 00 05 13 53 8F 18 00
|
||||||
|
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 0E 2A 15 9E CC 00 00 00 01 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 1E 55 B0 2F 00 00 00 01 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 2A 15 9E CC 00 00 00 02 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 03 D5 30 56 00 00 00 02 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 3F 57 76 9F 00 00 00 03 93 56 92 6E 96 B3 97 70 00 00 00 00 00 00 38 D9 0E C4 00 00 00 03 87 64 83 78 83 42 00 00 00 00 00 00 00 00 23 F3 B9 77 00 00 00 04 82 B3 82 CC 82 DC 82 E9 81 99 00 00 00 00 3F 1B 17 9C 00 00 00 04 82 B1 82 A4 82 BD 00 00 00 00 00 00 00 00 00 B9 F9 C0 00 00 00 05 82 CD 82 E9 82 A9 00 00 00 00 00 00 00 00 23 9F 9A EA 00 00 00 05 83 70 83 62 83 4C 83 83 83 49 00 00 00 00 38 D9 0E C4 00 00 00 06 87 64 83 78 83 42 00 00 00 00 00 00 00 00 1E 55 B0 2F 00 00 00 06 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 03 D5 30 56 00 00 00 07 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 02 D3 B8 77 00 00 00 07 6F 77 6C 32 35 32 35 00 00 00 00 00 00 00
|
||||||
|
data, _ := hex.DecodeString("0A218EAD0000000000000000000000010000000000000000")
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
|
func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfGetTinyBin)
|
||||||
|
// requested after conquest quests
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfPostTinyBin)
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
}
|
||||||
|
|
||||||
func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func cleanupDiva(s *Session) {
|
|||||||
|
|
||||||
func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
||||||
timestamps := make([]uint32, 6)
|
timestamps := make([]uint32, 6)
|
||||||
midnight := Time_Current_Midnight()
|
midnight := TimeMidnight()
|
||||||
if debug && start <= 3 {
|
if debug && start <= 3 {
|
||||||
midnight := uint32(midnight.Unix())
|
midnight := uint32(midnight.Unix())
|
||||||
switch start {
|
switch start {
|
||||||
@@ -43,7 +43,7 @@ func generateDivaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
|||||||
}
|
}
|
||||||
return timestamps
|
return timestamps
|
||||||
}
|
}
|
||||||
if start == 0 || Time_Current_Adjusted().Unix() > int64(start)+2977200 {
|
if start == 0 || TimeAdjusted().Unix() > int64(start)+2977200 {
|
||||||
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())
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
|
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
|
||||||
|
|
||||||
var features []activeFeature
|
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())
|
rows, _ := s.server.db.Queryx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1 OR start_time=$2`, TimeMidnight(), TimeMidnight().Add(24*time.Hour))
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var feature activeFeature
|
var feature activeFeature
|
||||||
rows.StructScan(&feature)
|
rows.StructScan(&feature)
|
||||||
@@ -71,19 +71,19 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
if len(features) < 2 {
|
if len(features) < 2 {
|
||||||
if len(features) == 0 {
|
if len(features) == 0 {
|
||||||
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
|
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
|
||||||
feature.StartTime = Time_Current_Midnight().Add(-24 * time.Hour)
|
feature.StartTime = TimeMidnight()
|
||||||
features = append(features, feature)
|
features = append(features, feature)
|
||||||
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
|
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
|
||||||
}
|
}
|
||||||
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
|
feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
|
||||||
feature.StartTime = Time_Current_Midnight()
|
feature.StartTime = TimeMidnight().Add(24 * time.Hour)
|
||||||
features = append(features, feature)
|
features = append(features, feature)
|
||||||
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
|
s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint8(2)
|
bf.WriteUint8(2)
|
||||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
|
bf.WriteUint32(uint32(TimeAdjusted().Add(-5 * time.Minute).Unix()))
|
||||||
for _, feature := range features {
|
for _, feature := range features {
|
||||||
bf.WriteUint32(uint32(feature.StartTime.Unix()))
|
bf.WriteUint32(uint32(feature.StartTime.Unix()))
|
||||||
bf.WriteUint32(feature.ActiveFeatures)
|
bf.WriteUint32(feature.ActiveFeatures)
|
||||||
@@ -119,129 +119,97 @@ func generateFeatureWeapons(count int) activeFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type loginBoost struct {
|
type loginBoost struct {
|
||||||
WeekReq, WeekCount uint8
|
WeekReq uint8 `db:"week_req"`
|
||||||
Available bool
|
WeekCount uint8
|
||||||
Expiration uint32
|
Active bool
|
||||||
|
Expiration time.Time `db:"expiration"`
|
||||||
|
Reset time.Time `db:"reset"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus)
|
pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus)
|
||||||
|
|
||||||
var loginBoostStatus []loginBoost
|
bf := byteframe.NewByteFrame()
|
||||||
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)
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
for boostState.Next() {
|
for rows.Next() {
|
||||||
var boost loginBoost
|
var temp loginBoost
|
||||||
err = boostState.Scan(&boost.WeekReq, &boost.WeekCount, &boost.Available, &boost.Expiration)
|
rows.StructScan(&temp)
|
||||||
if err != nil {
|
loginBoosts = append(loginBoosts, temp)
|
||||||
panic(err)
|
}
|
||||||
|
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)
|
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{})
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp := byteframe.NewByteFrame()
|
|
||||||
CurrentWeek := Time_Current_Week_uint8()
|
for _, boost := range loginBoosts {
|
||||||
for d := range loginBoostStatus {
|
// Reset if next week
|
||||||
if CurrentWeek == 1 && loginBoostStatus[d].WeekCount <= 5 {
|
if !boost.Reset.IsZero() && boost.Reset.Before(TimeAdjusted()) {
|
||||||
loginBoostStatus[d].WeekCount = 0
|
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)
|
bf.WriteUint8(boost.WeekReq)
|
||||||
if err != nil {
|
bf.WriteBool(boost.Active)
|
||||||
panic(err)
|
bf.WriteUint8(boost.WeekCount)
|
||||||
}
|
if !boost.Reset.IsZero() {
|
||||||
|
bf.WriteUint32(uint32(boost.Expiration.Unix()))
|
||||||
|
} else {
|
||||||
|
bf.WriteUint32(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, v := range loginBoostStatus {
|
|
||||||
if insert {
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
_, 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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {
|
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)
|
pkt := p.(*mhfpacket.MsgMhfUseKeepLoginBoost)
|
||||||
var t = time.Now().In(time.FixedZone("UTC+1", 1*60*60))
|
var expiration time.Time
|
||||||
resp := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
resp.WriteUint8(0)
|
bf.WriteUint8(0)
|
||||||
|
|
||||||
// response is end timestamp based on input
|
|
||||||
switch pkt.BoostWeekUsed {
|
switch pkt.BoostWeekUsed {
|
||||||
case 1:
|
case 1:
|
||||||
t = t.Add(120 * time.Minute)
|
fallthrough
|
||||||
resp.WriteUint32(uint32(t.Unix()))
|
|
||||||
case 2:
|
|
||||||
t = t.Add(240 * time.Minute)
|
|
||||||
resp.WriteUint32(uint32(t.Unix()))
|
|
||||||
case 3:
|
case 3:
|
||||||
t = t.Add(120 * time.Minute)
|
expiration = TimeAdjusted().Add(120 * time.Minute)
|
||||||
resp.WriteUint32(uint32(t.Unix()))
|
|
||||||
case 4:
|
case 4:
|
||||||
t = t.Add(180 * time.Minute)
|
expiration = TimeAdjusted().Add(180 * time.Minute)
|
||||||
resp.WriteUint32(uint32(t.Unix()))
|
case 2:
|
||||||
|
fallthrough
|
||||||
case 5:
|
case 5:
|
||||||
t = t.Add(240 * time.Minute)
|
expiration = TimeAdjusted().Add(240 * time.Minute)
|
||||||
resp.WriteUint32(uint32(t.Unix()))
|
|
||||||
}
|
}
|
||||||
_, 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)
|
bf.WriteUint32(uint32(expiration.Unix()))
|
||||||
if err != nil {
|
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)
|
||||||
panic(err)
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|||||||
@@ -12,22 +12,25 @@ import (
|
|||||||
|
|
||||||
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)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
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)
|
||||||
|
var data []byte
|
||||||
resp := byteframe.NewByteFrame()
|
s.server.db.QueryRow(`SELECT mezfes FROM characters WHERE id=$1`, s.charID).Scan(&data)
|
||||||
resp.WriteUint32(0) // Unk
|
bf := byteframe.NewByteFrame()
|
||||||
|
if len(data) > 0 {
|
||||||
resp.WriteUint8(2) // Count of the next 2 uint32s
|
bf.WriteBytes(data)
|
||||||
resp.WriteUint32(0)
|
} else {
|
||||||
resp.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
|
bf.WriteUint8(2)
|
||||||
resp.WriteUint32(0) // Unk
|
bf.WriteUint32(0)
|
||||||
|
bf.WriteUint32(0)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
bf.WriteUint32(0)
|
||||||
|
}
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -38,7 +41,7 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
// Unk
|
// Unk
|
||||||
// Start?
|
// Start?
|
||||||
// End?
|
// End?
|
||||||
midnight := Time_Current_Midnight()
|
midnight := TimeMidnight()
|
||||||
switch state {
|
switch state {
|
||||||
case 1:
|
case 1:
|
||||||
bf.WriteUint32(uint32(midnight.Unix()))
|
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()))
|
bf.WriteUint32(uint32(midnight.Add(7 * 24 * time.Hour).Unix()))
|
||||||
default:
|
default:
|
||||||
bf.WriteBytes(make([]byte, 16))
|
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.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(Time_Current_Adjusted().Unix())) // TS Current Time
|
bf.WriteUint32(uint32(TimeAdjusted().Unix())) // TS Current Time
|
||||||
bf.WriteUint8(3)
|
bf.WriteUint8(3)
|
||||||
ps.Uint8(bf, "", false)
|
ps.Uint8(bf, "", false)
|
||||||
bf.WriteUint16(0) // numEvents
|
bf.WriteUint16(0) // numEvents
|
||||||
@@ -98,7 +101,7 @@ func cleanupFesta(s *Session) {
|
|||||||
|
|
||||||
func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
||||||
timestamps := make([]uint32, 5)
|
timestamps := make([]uint32, 5)
|
||||||
midnight := Time_Current_Midnight()
|
midnight := TimeMidnight()
|
||||||
if debug && start <= 3 {
|
if debug && start <= 3 {
|
||||||
midnight := uint32(midnight.Unix())
|
midnight := uint32(midnight.Unix())
|
||||||
switch start {
|
switch start {
|
||||||
@@ -123,7 +126,7 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 {
|
|||||||
}
|
}
|
||||||
return timestamps
|
return timestamps
|
||||||
}
|
}
|
||||||
if start == 0 || Time_Current_Adjusted().Unix() > int64(start)+2977200 {
|
if start == 0 || TimeAdjusted().Unix() > int64(start)+2977200 {
|
||||||
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())
|
||||||
@@ -167,7 +170,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
timestamps = generateFestaTimestamps(s, start, false)
|
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))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -180,7 +183,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
for _, timestamp := range timestamps {
|
for _, timestamp := range timestamps {
|
||||||
bf.WriteUint32(timestamp)
|
bf.WriteUint32(timestamp)
|
||||||
}
|
}
|
||||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix()))
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
bf.WriteUint8(4)
|
bf.WriteUint8(4)
|
||||||
ps.Uint8(bf, "", false)
|
ps.Uint8(bf, "", false)
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
|
|||||||
@@ -1732,57 +1732,59 @@ func handleMsgMhfCancelGuildMissionTarget(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GuildMeal struct {
|
type GuildMeal struct {
|
||||||
ID uint32 `db:"id"`
|
ID uint32 `db:"id"`
|
||||||
MealID uint32 `db:"meal_id"`
|
MealID uint32 `db:"meal_id"`
|
||||||
Level uint32 `db:"level"`
|
Level uint32 `db:"level"`
|
||||||
Expires uint32 `db:"expires"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfLoadGuildCooking)
|
pkt := p.(*mhfpacket.MsgMhfLoadGuildCooking)
|
||||||
|
|
||||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
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 {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get guild meals from db", zap.Error(err))
|
s.logger.Error("Failed to get guild meals from db", zap.Error(err))
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
temp := byteframe.NewByteFrame()
|
var meals []GuildMeal
|
||||||
count := 0
|
var temp GuildMeal
|
||||||
for data.Next() {
|
for data.Next() {
|
||||||
mealData := &GuildMeal{}
|
err = data.StructScan(&temp)
|
||||||
err = data.StructScan(&mealData)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if mealData.Expires > uint32(Time_Current_Adjusted().Add(-60*time.Minute).Unix()) {
|
if temp.CreatedAt.Add(60 * time.Minute).After(TimeAdjusted()) {
|
||||||
count++
|
meals = append(meals, temp)
|
||||||
temp.WriteUint32(mealData.ID)
|
|
||||||
temp.WriteUint32(mealData.MealID)
|
|
||||||
temp.WriteUint32(mealData.Level)
|
|
||||||
temp.WriteUint32(mealData.Expires)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint16(uint16(count))
|
bf.WriteUint16(uint16(len(meals)))
|
||||||
bf.WriteBytes(temp.Data())
|
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())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildCooking)
|
pkt := p.(*mhfpacket.MsgMhfRegistGuildCooking)
|
||||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
|
currentTime := TimeAdjusted()
|
||||||
if pkt.OverwriteID != 0 {
|
if pkt.OverwriteID != 0 {
|
||||||
_, err := s.server.db.Exec("DELETE FROM guild_meals WHERE id = $1", pkt.OverwriteID)
|
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)
|
||||||
if err != nil {
|
} else {
|
||||||
s.logger.Error("Failed to delete meal in db", zap.Error(err))
|
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())
|
bf := byteframe.NewByteFrame()
|
||||||
if err != nil {
|
bf.WriteUint16(1)
|
||||||
s.logger.Error("Failed to register meal in db", zap.Error(err))
|
bf.WriteUint32(pkt.OverwriteID)
|
||||||
}
|
bf.WriteUint32(uint32(pkt.MealID))
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x00})
|
bf.WriteUint32(uint32(pkt.Success))
|
||||||
|
bf.WriteUint32(uint32(currentTime.Unix()))
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -1819,59 +1821,51 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MessageBoardPost struct {
|
type MessageBoardPost struct {
|
||||||
Type uint32 `db:"post_type"`
|
ID uint32 `db:"id"`
|
||||||
StampID uint32 `db:"stamp_id"`
|
StampID uint32 `db:"stamp_id"`
|
||||||
Title string `db:"title"`
|
Title string `db:"title"`
|
||||||
Body string `db:"body"`
|
Body string `db:"body"`
|
||||||
AuthorID uint32 `db:"author_id"`
|
AuthorID uint32 `db:"author_id"`
|
||||||
Timestamp uint64 `db:"created_at"`
|
Timestamp time.Time `db:"created_at"`
|
||||||
LikedBy string `db:"liked_by"`
|
LikedBy string `db:"liked_by"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMessageBoard)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMessageBoard)
|
||||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
||||||
|
if pkt.BoardType == 1 {
|
||||||
msgs, err := s.server.db.Queryx("SELECT post_type, stamp_id, title, body, author_id, (EXTRACT(epoch FROM created_at)::int) as created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
|
pkt.MaxPosts = 4
|
||||||
|
}
|
||||||
|
msgs, err := s.server.db.Queryx("SELECT id, stamp_id, title, body, author_id, created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get guild messages from db", zap.Error(err))
|
s.logger.Error("Failed to get guild messages from db", zap.Error(err))
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s.server.db.Exec("UPDATE characters SET guild_post_checked = now() WHERE id = $1", s.charID)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
noMsgs := true
|
var postCount uint32
|
||||||
postCount := 0
|
|
||||||
for msgs.Next() {
|
for msgs.Next() {
|
||||||
noMsgs = false
|
|
||||||
postCount++
|
|
||||||
postData := &MessageBoardPost{}
|
postData := &MessageBoardPost{}
|
||||||
msgs.StructScan(&postData)
|
err = msgs.StructScan(&postData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bf.WriteUint32(postData.Type)
|
postCount++
|
||||||
|
bf.WriteUint32(postData.ID)
|
||||||
bf.WriteUint32(postData.AuthorID)
|
bf.WriteUint32(postData.AuthorID)
|
||||||
bf.WriteUint64(postData.Timestamp)
|
bf.WriteUint32(0)
|
||||||
likedBySlice := strings.Split(postData.LikedBy, ",")
|
bf.WriteUint32(uint32(postData.Timestamp.Unix()))
|
||||||
if likedBySlice[0] == "" {
|
bf.WriteUint32(uint32(stringsupport.CSVLength(postData.LikedBy)))
|
||||||
bf.WriteUint32(0)
|
|
||||||
} else {
|
|
||||||
bf.WriteUint32(uint32(len(likedBySlice)))
|
|
||||||
}
|
|
||||||
bf.WriteBool(stringsupport.CSVContains(postData.LikedBy, int(s.charID)))
|
bf.WriteBool(stringsupport.CSVContains(postData.LikedBy, int(s.charID)))
|
||||||
bf.WriteUint32(postData.StampID)
|
bf.WriteUint32(postData.StampID)
|
||||||
ps.Uint32(bf, postData.Title, true)
|
ps.Uint32(bf, postData.Title, true)
|
||||||
ps.Uint32(bf, postData.Body, true)
|
ps.Uint32(bf, postData.Body, true)
|
||||||
}
|
}
|
||||||
if noMsgs {
|
data := byteframe.NewByteFrame()
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
data.WriteUint32(postCount)
|
||||||
} else {
|
data.WriteBytes(bf.Data())
|
||||||
data := byteframe.NewByteFrame()
|
doAckBufSucceed(s, pkt.AckHandle, data.Data())
|
||||||
data.WriteUint32(uint32(postCount))
|
|
||||||
data.WriteBytes(bf.Data())
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data.Data())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -1886,98 +1880,58 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var titleConv, bodyConv string
|
|
||||||
switch pkt.MessageOp {
|
switch pkt.MessageOp {
|
||||||
case 0: // Create message
|
case 0: // Create message
|
||||||
postType := bf.ReadUint32() // 0 = message, 1 = news
|
postType := bf.ReadUint32() // 0 = message, 1 = news
|
||||||
stampId := bf.ReadUint32()
|
stampID := bf.ReadUint32()
|
||||||
titleLength := bf.ReadUint32()
|
titleLength := bf.ReadUint32()
|
||||||
bodyLength := bf.ReadUint32()
|
bodyLength := bf.ReadUint32()
|
||||||
title := bf.ReadBytes(uint(titleLength))
|
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
|
||||||
body := bf.ReadBytes(uint(bodyLength))
|
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
|
||||||
titleConv = stringsupport.SJISToUTF8(title)
|
s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, stampID, postType, title, body)
|
||||||
bodyConv = stringsupport.SJISToUTF8(body)
|
// TODO: if there are too many messages, purge excess
|
||||||
_, err := s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, int(stampId), int(postType), titleConv, bodyConv)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to add new guild message to db", zap.Error(err))
|
|
||||||
}
|
|
||||||
/* TODO: if there are too many messages, purge excess
|
|
||||||
_, err = s.server.db.Exec("")
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to remove excess guild messages from db", zap.Error(err))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
case 1: // Delete message
|
case 1: // Delete message
|
||||||
postType := bf.ReadUint32()
|
postID := bf.ReadUint32()
|
||||||
timestamp := bf.ReadUint64()
|
s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", postID)
|
||||||
_, err := s.server.db.Exec("DELETE FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to delete guild message from db", zap.Error(err))
|
|
||||||
}
|
|
||||||
case 2: // Update message
|
case 2: // Update message
|
||||||
postType := bf.ReadUint32()
|
postID := bf.ReadUint32()
|
||||||
timestamp := bf.ReadUint64()
|
bf.ReadBytes(8)
|
||||||
titleLength := bf.ReadUint32()
|
titleLength := bf.ReadUint32()
|
||||||
bodyLength := bf.ReadUint32()
|
bodyLength := bf.ReadUint32()
|
||||||
title := bf.ReadBytes(uint(titleLength))
|
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
|
||||||
body := bf.ReadBytes(uint(bodyLength))
|
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
|
||||||
titleConv = stringsupport.SJISToUTF8(title)
|
s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", title, body, postID)
|
||||||
bodyConv = stringsupport.SJISToUTF8(body)
|
|
||||||
_, err := s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE post_type = $3 AND (EXTRACT(epoch FROM created_at)::int) = $4 AND guild_id = $5", titleConv, bodyConv, int(postType), int(timestamp), guild.ID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to update guild message in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
case 3: // Update stamp
|
case 3: // Update stamp
|
||||||
postType := bf.ReadUint32()
|
postID := bf.ReadUint32()
|
||||||
timestamp := bf.ReadUint64()
|
bf.ReadBytes(8)
|
||||||
stampId := bf.ReadUint32()
|
stampID := bf.ReadUint32()
|
||||||
_, err := s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", int(stampId), int(postType), int(timestamp), guild.ID)
|
s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", stampID, postID)
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to update guild message stamp in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
case 4: // Like message
|
case 4: // Like message
|
||||||
postType := bf.ReadUint32()
|
postID := bf.ReadUint32()
|
||||||
timestamp := bf.ReadUint64()
|
bf.ReadBytes(8)
|
||||||
likeState := bf.ReadBool()
|
likeState := bf.ReadBool()
|
||||||
var likedBy string
|
var likedBy string
|
||||||
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID).Scan(&likedBy)
|
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", postID).Scan(&likedBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get guild message like data from db", zap.Error(err))
|
s.logger.Error("Failed to get guild message like data from db", zap.Error(err))
|
||||||
} else {
|
} else {
|
||||||
if likeState {
|
if likeState {
|
||||||
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
|
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
|
||||||
_, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID)
|
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to like guild message in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
|
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
|
||||||
_, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID)
|
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to unlike guild message in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 5: // Check for new messages
|
case 5: // Check for new messages
|
||||||
var timeChecked int
|
var timeChecked time.Time
|
||||||
var newPosts int
|
var newPosts int
|
||||||
err := s.server.db.QueryRow("SELECT (EXTRACT(epoch FROM guild_post_checked)::int) FROM characters WHERE id = $1", s.charID).Scan(&timeChecked)
|
err := s.server.db.QueryRow("SELECT guild_post_checked FROM characters WHERE id = $1", s.charID).Scan(&timeChecked)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
s.logger.Error("Failed to get last guild post check timestamp from db", zap.Error(err))
|
s.server.db.QueryRow("SELECT COUNT(*) FROM guild_posts WHERE guild_id = $1 AND (EXTRACT(epoch FROM created_at)::int) > $2", guild.ID, timeChecked.Unix()).Scan(&newPosts)
|
||||||
} else {
|
if newPosts > 0 {
|
||||||
_, err = s.server.db.Exec("UPDATE characters SET guild_post_checked = $1 WHERE id = $2", time.Now(), s.charID)
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
|
||||||
if err != nil {
|
return
|
||||||
s.logger.Error("Failed to update guild post check timestamp in db", zap.Error(err))
|
|
||||||
} else {
|
|
||||||
err = s.server.db.QueryRow("SELECT COUNT(*) FROM guild_posts WHERE guild_id = $1 AND (EXTRACT(epoch FROM created_at)::int) > $2 AND author_id != $3", guild.ID, timeChecked, s.charID).Scan(&newPosts)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to check for new guild posts in db", zap.Error(err))
|
|
||||||
} else {
|
|
||||||
if newPosts > 0 {
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
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)
|
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 {
|
if err != nil {
|
||||||
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
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) {
|
func handleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva)
|
pkt := p.(*mhfpacket.MsgMhfRegistGuildAdventureDiva)
|
||||||
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
|
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 {
|
if err != nil {
|
||||||
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
s.logger.Error("Failed to register guild adventure", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
hunts := 0
|
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() {
|
for rows.Next() {
|
||||||
hunt := &TreasureHunt{}
|
hunt := &TreasureHunt{}
|
||||||
err = rows.StructScan(&hunt)
|
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)",
|
_, 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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,10 @@ func treasureHuntUnregister(s *Session) {
|
|||||||
}
|
}
|
||||||
var huntID int
|
var huntID int
|
||||||
var hunters string
|
var hunters string
|
||||||
rows, _ := s.server.db.Queryx("SELECT id, hunters FROM guild_hunts WHERE guild_id=$1", guild.ID)
|
rows, err := s.server.db.Queryx("SELECT id, hunters FROM guild_hunts WHERE guild_id=$1", guild.ID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
rows.Scan(&huntID, &hunters)
|
rows.Scan(&huntID, &hunters)
|
||||||
hunters = stringsupport.CSVRemove(hunters, int(s.charID))
|
hunters = stringsupport.CSVRemove(hunters, int(s.charID))
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
Unk uint32
|
Unk uint32
|
||||||
Timestamp uint32
|
Timestamp uint32
|
||||||
}{
|
}{
|
||||||
{0, uint32(Time_Current_Midnight().Add(-12 * time.Hour).Unix())},
|
{0, uint32(TimeMidnight().Add(-12 * time.Hour).Unix())},
|
||||||
{0, uint32(Time_Current_Midnight().Add(12 * time.Hour).Unix())},
|
{0, uint32(TimeMidnight().Add(12 * time.Hour).Unix())},
|
||||||
{0, uint32(Time_Current_Midnight().Add(36 * time.Hour).Unix())},
|
{0, uint32(TimeMidnight().Add(36 * time.Hour).Unix())},
|
||||||
}
|
}
|
||||||
bf.WriteUint8(uint8(len(legendDispatch)))
|
bf.WriteUint8(uint8(len(legendDispatch)))
|
||||||
for _, dispatch := range legendDispatch {
|
for _, dispatch := range legendDispatch {
|
||||||
@@ -164,8 +164,8 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf.WriteUint32(pactID)
|
bf.WriteUint32(pactID)
|
||||||
bf.WriteUint32(cid)
|
bf.WriteUint32(cid)
|
||||||
bf.WriteBool(false) // ?
|
bf.WriteBool(false) // ?
|
||||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -8).Unix()))
|
bf.WriteUint32(uint32(TimeAdjusted().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 * -1).Unix()))
|
||||||
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||||
} else {
|
} else {
|
||||||
bf.WriteUint8(0)
|
bf.WriteUint8(0)
|
||||||
@@ -180,8 +180,8 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
rows.Scan(&name, &cid, &pactID)
|
rows.Scan(&name, &cid, &pactID)
|
||||||
temp.WriteUint32(pactID)
|
temp.WriteUint32(pactID)
|
||||||
temp.WriteUint32(cid)
|
temp.WriteUint32(cid)
|
||||||
temp.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -8).Unix()))
|
temp.WriteUint32(uint32(TimeAdjusted().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 * -1).Unix()))
|
||||||
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||||
}
|
}
|
||||||
bf.WriteUint8(loans)
|
bf.WriteUint8(loans)
|
||||||
@@ -346,7 +346,7 @@ func getGuildAirouList(s *Session) []CatDefinition {
|
|||||||
FROM guild_hunts gh
|
FROM guild_hunts gh
|
||||||
INNER JOIN characters c
|
INNER JOIN characters c
|
||||||
ON gh.host_id = c.id
|
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 {
|
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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,3 @@ func handleMsgMhfAcquireMonthlyReward(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {}
|
|
||||||
|
|
||||||
func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) {}
|
|
||||||
|
|||||||
@@ -2,14 +2,10 @@ package channelserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
ps "erupe-ce/common/pascalstring"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"github.com/lib/pq"
|
"math/rand"
|
||||||
"github.com/sachaos/lottery"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ShopItem struct {
|
type ShopItem struct {
|
||||||
@@ -28,16 +24,36 @@ type ShopItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Gacha struct {
|
type Gacha struct {
|
||||||
ID uint32 `db:"id"`
|
ID uint32 `db:"id"`
|
||||||
MinGR uint32 `db:"min_gr"`
|
MinGR uint32 `db:"min_gr"`
|
||||||
MinHR uint32 `db:"min_hr"`
|
MinHR uint32 `db:"min_hr"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
Link1 string `db:"link1"`
|
URLBanner string `db:"url_banner"`
|
||||||
Link2 string `db:"link2"`
|
URLFeature string `db:"url_feature"`
|
||||||
Link3 string `db:"link3"`
|
URLThumbnail string `db:"url_thumbnail"`
|
||||||
Icon uint16 `db:"icon"`
|
Wide bool `db:"wide"`
|
||||||
Type uint16 `db:"type"`
|
Recommended bool `db:"recommended"`
|
||||||
Hide bool `db:"hide"`
|
GachaType uint8 `db:"gacha_type"`
|
||||||
|
Hidden bool `db:"hidden"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GachaEntry struct {
|
||||||
|
EntryType uint8 `db:"entry_type"`
|
||||||
|
ID uint32 `db:"id"`
|
||||||
|
ItemType uint8 `db:"item_type"`
|
||||||
|
ItemNumber uint16 `db:"item_number"`
|
||||||
|
ItemQuantity uint16 `db:"item_quantity"`
|
||||||
|
Weight float64 `db:"weight"`
|
||||||
|
Rarity uint8 `db:"rarity"`
|
||||||
|
Rolls uint8 `db:"rolls"`
|
||||||
|
FrontierPoints uint16 `db:"frontier_points"`
|
||||||
|
DailyLimit uint8 `db:"daily_limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GachaItem struct {
|
||||||
|
ItemType uint8 `db:"item_type"`
|
||||||
|
ItemID uint16 `db:"item_id"`
|
||||||
|
Quantity uint16 `db:"quantity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
|
||||||
@@ -55,7 +71,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
switch pkt.ShopType {
|
switch pkt.ShopType {
|
||||||
case 1: // Running gachas
|
case 1: // Running gachas
|
||||||
var count uint16
|
var count uint16
|
||||||
shopEntries, err := s.server.db.Queryx("SELECT id, min_gr, min_hr, name, link1, link2, link3, icon, type, hide FROM gacha_shop")
|
shopEntries, 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")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
@@ -74,12 +90,18 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
resp.WriteUint32(gacha.MinHR)
|
resp.WriteUint32(gacha.MinHR)
|
||||||
resp.WriteUint32(0) // only 0 in known packet
|
resp.WriteUint32(0) // only 0 in known packet
|
||||||
ps.Uint8(resp, gacha.Name, true)
|
ps.Uint8(resp, gacha.Name, true)
|
||||||
ps.Uint8(resp, gacha.Link1, false)
|
ps.Uint8(resp, gacha.URLBanner, false)
|
||||||
ps.Uint8(resp, gacha.Link2, false)
|
ps.Uint8(resp, gacha.URLFeature, false)
|
||||||
resp.WriteBool(gacha.Hide)
|
resp.WriteBool(gacha.Wide)
|
||||||
ps.Uint8(resp, gacha.Link3, false)
|
ps.Uint8(resp, gacha.URLThumbnail, false)
|
||||||
resp.WriteUint16(gacha.Icon)
|
resp.WriteUint8(0) // Unk
|
||||||
resp.WriteUint16(gacha.Type)
|
if gacha.Recommended {
|
||||||
|
resp.WriteUint8(2)
|
||||||
|
} else {
|
||||||
|
resp.WriteUint8(0)
|
||||||
|
}
|
||||||
|
resp.WriteUint8(gacha.GachaType)
|
||||||
|
resp.WriteBool(gacha.Hidden)
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
resp.Seek(0, 0)
|
resp.Seek(0, 0)
|
||||||
@@ -87,47 +109,62 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
resp.WriteUint16(count)
|
resp.WriteUint16(count)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||||
case 2: // Actual gacha
|
case 2: // Actual gacha
|
||||||
shopEntries, err := s.server.db.Query("SELECT entryType, itemhash, currType, currNumber, currQuant, percentage, rarityIcon, rollsCount, itemCount, dailyLimit, itemType, itemId, quantity FROM gacha_shop_items WHERE shophash=$1", pkt.ShopID)
|
bf := byteframe.NewByteFrame()
|
||||||
|
bf.WriteUint32(pkt.ShopID)
|
||||||
|
var gachaType int
|
||||||
|
s.server.db.QueryRow(`SELECT gacha_type FROM gacha_shop WHERE id = $1`, pkt.ShopID).Scan(&gachaType)
|
||||||
|
entries, err := s.server.db.Queryx(`SELECT entry_type, id, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points 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 entryType, currType, rarityIcon, rollsCount, itemCount, dailyLimit uint8
|
var divisor float64
|
||||||
var currQuant, currNumber, percentage uint16
|
s.server.db.QueryRow(`SELECT COALESCE(SUM(weight) / 100000.0, 0) AS chance FROM gacha_entries WHERE gacha_id = $1`, pkt.ShopID).Scan(&divisor)
|
||||||
var itemhash uint32
|
var entryCount uint16
|
||||||
var itemType, itemId, quantity pq.Int64Array
|
bf.WriteUint16(0)
|
||||||
var count uint16
|
gachaEntry := GachaEntry{}
|
||||||
resp := byteframe.NewByteFrame()
|
gachaItem := GachaItem{}
|
||||||
resp.WriteUint32(pkt.ShopID)
|
for entries.Next() {
|
||||||
resp.WriteUint16(0) // total defs
|
entryCount++
|
||||||
for shopEntries.Next() {
|
entries.StructScan(&gachaEntry)
|
||||||
err = shopEntries.Scan(&entryType, &itemhash, &currType, &currNumber, &currQuant, &percentage, &rarityIcon, &rollsCount, &itemCount, &dailyLimit, (*pq.Int64Array)(&itemType), (*pq.Int64Array)(&itemId), (*pq.Int64Array)(&quantity))
|
bf.WriteUint8(gachaEntry.EntryType)
|
||||||
|
bf.WriteUint32(gachaEntry.ID)
|
||||||
|
bf.WriteUint8(gachaEntry.ItemType)
|
||||||
|
bf.WriteUint16(0)
|
||||||
|
bf.WriteUint16(gachaEntry.ItemNumber)
|
||||||
|
bf.WriteUint16(gachaEntry.ItemQuantity)
|
||||||
|
if gachaType >= 4 { // If box
|
||||||
|
bf.WriteUint16(1)
|
||||||
|
} else {
|
||||||
|
bf.WriteUint16(uint16(gachaEntry.Weight / divisor))
|
||||||
|
}
|
||||||
|
bf.WriteUint8(gachaEntry.Rarity)
|
||||||
|
bf.WriteUint8(gachaEntry.Rolls)
|
||||||
|
|
||||||
|
var itemCount uint8
|
||||||
|
temp := byteframe.NewByteFrame()
|
||||||
|
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, gachaEntry.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
bf.WriteUint8(0)
|
||||||
|
} else {
|
||||||
|
for items.Next() {
|
||||||
|
itemCount++
|
||||||
|
items.StructScan(&gachaItem)
|
||||||
|
temp.WriteUint16(uint16(gachaItem.ItemType))
|
||||||
|
temp.WriteUint16(gachaItem.ItemID)
|
||||||
|
temp.WriteUint16(gachaItem.Quantity)
|
||||||
|
}
|
||||||
|
bf.WriteUint8(itemCount)
|
||||||
}
|
}
|
||||||
resp.WriteUint8(entryType)
|
|
||||||
resp.WriteUint32(itemhash)
|
bf.WriteUint16(gachaEntry.FrontierPoints)
|
||||||
resp.WriteUint8(currType)
|
bf.WriteUint8(gachaEntry.DailyLimit)
|
||||||
resp.WriteUint16(0) // unk, always 0 in existing packets
|
bf.WriteUint8(0)
|
||||||
resp.WriteUint16(currNumber) // it's either item ID or quantity for gacha coins
|
bf.WriteBytes(temp.Data())
|
||||||
resp.WriteUint16(currQuant) // only for item ID
|
|
||||||
resp.WriteUint16(percentage)
|
|
||||||
resp.WriteUint8(rarityIcon)
|
|
||||||
resp.WriteUint8(rollsCount)
|
|
||||||
resp.WriteUint8(itemCount)
|
|
||||||
resp.WriteUint16(0) // unk, always 0 in existing packets
|
|
||||||
resp.WriteUint8(dailyLimit)
|
|
||||||
resp.WriteUint8(0) // unk, always 0 in existing packets
|
|
||||||
for i := 0; i < int(itemCount); i++ {
|
|
||||||
resp.WriteUint16(uint16(itemType[i])) // unk, always 0 in existing packets
|
|
||||||
resp.WriteUint16(uint16(itemId[i])) // unk, always 0 in existing packets
|
|
||||||
resp.WriteUint16(uint16(quantity[i])) // unk, always 0 in existing packets
|
|
||||||
}
|
|
||||||
count++
|
|
||||||
}
|
}
|
||||||
resp.Seek(4, 0)
|
bf.Seek(4, 0)
|
||||||
resp.WriteUint16(count)
|
bf.WriteUint16(entryCount)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
case 4: // N Points, 0-6
|
case 4: // N Points, 0-6
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
case 5: // GCP->Item, 0-6
|
case 5: // GCP->Item, 0-6
|
||||||
@@ -206,124 +243,363 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
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(0)
|
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_prem, 0), COALESCE(gacha_trial,0) FROM characters WHERE id=$1", s.charID).Scan(&fp, &gp, >)
|
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, >)
|
||||||
resp := byteframe.NewByteFrame()
|
resp := byteframe.NewByteFrame()
|
||||||
resp.WriteUint32(gp) // Real Gacha Points?
|
resp.WriteUint32(gp)
|
||||||
resp.WriteUint32(gt) // Trial Gacha Point?
|
resp.WriteUint32(gt)
|
||||||
resp.WriteUint32(fp) // Frontier Points?
|
resp.WriteUint32(fp)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
type gachaItem struct {
|
func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) {
|
||||||
itemhash uint32
|
pkt := p.(*mhfpacket.MsgMhfUseGachaPoint)
|
||||||
percentage uint16
|
if pkt.TrialCoins > 0 {
|
||||||
rarityIcon byte
|
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)
|
||||||
itemCount byte
|
}
|
||||||
itemType pq.Int64Array
|
if pkt.PremiumCoins > 0 {
|
||||||
itemId pq.Int64Array
|
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)
|
||||||
quantity pq.Int64Array
|
}
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i gachaItem) Weight() int {
|
func spendGachaCoin(s *Session, quantity uint16) {
|
||||||
return int(i.percentage)
|
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(>)
|
||||||
|
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)
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func transactGacha(s *Session, gachaID uint32, rollID uint8) (error, int) {
|
||||||
|
var itemType uint8
|
||||||
|
var itemNumber uint16
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
return err, 0
|
||||||
|
}
|
||||||
|
switch itemType {
|
||||||
|
/*
|
||||||
|
valid types that need manual savedata manipulation:
|
||||||
|
- Ryoudan Points
|
||||||
|
- Bond Points
|
||||||
|
- Image Change Points
|
||||||
|
valid types that work (no additional code needed):
|
||||||
|
- Tore Points
|
||||||
|
- Festa Points
|
||||||
|
*/
|
||||||
|
case 17:
|
||||||
|
_ = addPointNetcafe(s, int(itemNumber)*-1)
|
||||||
|
case 19:
|
||||||
|
fallthrough
|
||||||
|
case 20:
|
||||||
|
spendGachaCoin(s, itemNumber)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return nil, rolls
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGuaranteedItems(s *Session, gachaID uint32, rollID uint8) []GachaItem {
|
||||||
|
var rewards []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)
|
||||||
|
if err == nil {
|
||||||
|
for items.Next() {
|
||||||
|
items.StructScan(&reward)
|
||||||
|
rewards = append(rewards, reward)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rewards
|
||||||
|
}
|
||||||
|
|
||||||
|
func addGachaItem(s *Session, items []GachaItem) {
|
||||||
|
var data []byte
|
||||||
|
s.server.db.QueryRow(`SELECT gacha_items FROM characters WHERE id = $1`, s.charID).Scan(&data)
|
||||||
|
if len(data) > 0 {
|
||||||
|
numItems := int(data[0])
|
||||||
|
data = data[1:]
|
||||||
|
oldItem := byteframe.NewByteFrameFromBytes(data)
|
||||||
|
for i := 0; i < numItems; i++ {
|
||||||
|
items = append(items, GachaItem{
|
||||||
|
ItemType: oldItem.ReadUint8(),
|
||||||
|
ItemID: oldItem.ReadUint16(),
|
||||||
|
Quantity: oldItem.ReadUint16(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newItem := byteframe.NewByteFrame()
|
||||||
|
newItem.WriteUint8(uint8(len(items)))
|
||||||
|
for i := range items {
|
||||||
|
newItem.WriteUint8(items[i].ItemType)
|
||||||
|
newItem.WriteUint16(items[i].ItemID)
|
||||||
|
newItem.WriteUint16(items[i].Quantity)
|
||||||
|
}
|
||||||
|
s.server.db.Exec(`UPDATE characters SET gacha_items = $1 WHERE id = $2`, newItem.Data(), s.charID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry, error) {
|
||||||
|
var chosen []GachaEntry
|
||||||
|
var totalWeight float64
|
||||||
|
for i := range entries {
|
||||||
|
totalWeight += entries[i].Weight
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if !isBox {
|
||||||
|
result := rand.Float64() * totalWeight
|
||||||
|
for _, entry := range entries {
|
||||||
|
result -= entry.Weight
|
||||||
|
if result < 0 {
|
||||||
|
chosen = append(chosen, entry)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result := rand.Intn(len(entries))
|
||||||
|
chosen = append(chosen, entries[result])
|
||||||
|
entries[result] = entries[len(entries)-1]
|
||||||
|
entries = entries[:len(entries)-1]
|
||||||
|
}
|
||||||
|
if rolls == len(chosen) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chosen, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfReceiveGachaItem)
|
||||||
|
var data []byte
|
||||||
|
err := s.server.db.QueryRow("SELECT COALESCE(gacha_items, $2) FROM characters WHERE id = $1", s.charID, []byte{0x00}).Scan(&data)
|
||||||
|
if err != nil {
|
||||||
|
data = []byte{0x00}
|
||||||
|
}
|
||||||
|
|
||||||
|
// I think there are still some edge cases where rewards can be nulled via overflow
|
||||||
|
if data[0] > 36 || len(data) > 181 {
|
||||||
|
resp := byteframe.NewByteFrame()
|
||||||
|
resp.WriteUint8(36)
|
||||||
|
resp.WriteBytes(data[1:181])
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||||
|
} else {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pkt.Freeze {
|
||||||
|
if data[0] > 36 || len(data) > 181 {
|
||||||
|
update := byteframe.NewByteFrame()
|
||||||
|
update.WriteUint8(uint8(len(data[181:]) / 5))
|
||||||
|
update.WriteBytes(data[181:])
|
||||||
|
s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", update.Data(), s.charID)
|
||||||
|
} else {
|
||||||
|
s.server.db.Exec("UPDATE characters SET gacha_items = null WHERE id = $1", s.charID)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfPlayNormalGacha)
|
pkt := p.(*mhfpacket.MsgMhfPlayNormalGacha)
|
||||||
// needs to query db for input gacha and return a result or number of results
|
bf := byteframe.NewByteFrame()
|
||||||
// uint8 number of results
|
var gachaEntries []GachaEntry
|
||||||
// uint8 item type
|
var entry GachaEntry
|
||||||
// uint16 item id
|
var rewards []GachaItem
|
||||||
// uint16 quantity
|
var reward GachaItem
|
||||||
|
err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType)
|
||||||
var currType, rarityIcon, rollsCount, itemCount byte
|
|
||||||
var currQuant, currNumber, percentage uint16
|
|
||||||
var itemhash uint32
|
|
||||||
var itemType, itemId, quantity pq.Int64Array
|
|
||||||
var items []lottery.Weighter
|
|
||||||
// get info for updating data and calculating costs
|
|
||||||
err := s.server.db.QueryRow("SELECT currType, currNumber, currQuant, rollsCount FROM gacha_shop_items WHERE shophash=$1 AND entryType=$2", pkt.GachaHash, pkt.RollType).Scan(&currType, &currNumber, &currQuant, &rollsCount)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// get existing items in storage if any
|
temp := byteframe.NewByteFrame()
|
||||||
var data []byte
|
entries, 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)
|
||||||
_ = s.server.db.QueryRow("SELECT gacha_items FROM characters WHERE id = $1", s.charID).Scan(&data)
|
|
||||||
if len(data) == 0 {
|
|
||||||
data = []byte{0x00}
|
|
||||||
}
|
|
||||||
// get gacha items and iterate through them for gacha roll
|
|
||||||
shopEntries, err := s.server.db.Query("SELECT itemhash, percentage, rarityIcon, itemCount, itemType, itemId, quantity FROM gacha_shop_items WHERE shophash=$1 AND entryType=100", pkt.GachaHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
for shopEntries.Next() {
|
for entries.Next() {
|
||||||
err = shopEntries.Scan(&itemhash, &percentage, &rarityIcon, &itemCount, (*pq.Int64Array)(&itemType), (*pq.Int64Array)(&itemId), (*pq.Int64Array)(&quantity))
|
entries.StructScan(&entry)
|
||||||
|
gachaEntries = append(gachaEntries, entry)
|
||||||
|
}
|
||||||
|
rewardEntries, err := getRandomEntries(gachaEntries, rolls, false)
|
||||||
|
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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
continue
|
||||||
}
|
}
|
||||||
items = append(items, &gachaItem{itemhash: itemhash, percentage: percentage, rarityIcon: rarityIcon, itemCount: itemCount, itemType: itemType, itemId: itemId, quantity: quantity})
|
for items.Next() {
|
||||||
}
|
items.StructScan(&reward)
|
||||||
// execute rolls, build response and update database
|
rewards = append(rewards, reward)
|
||||||
results := byte(0)
|
temp.WriteUint8(reward.ItemType)
|
||||||
resp := byteframe.NewByteFrame()
|
temp.WriteUint16(reward.ItemID)
|
||||||
dbUpdate := byteframe.NewByteFrame()
|
temp.WriteUint16(reward.Quantity)
|
||||||
resp.WriteUint8(0) // results go here later
|
temp.WriteUint8(entry.Rarity)
|
||||||
l := lottery.NewDefaultLottery()
|
|
||||||
for x := 0; x < int(rollsCount); x++ {
|
|
||||||
ind := l.Draw(items)
|
|
||||||
results += items[ind].(*gachaItem).itemCount
|
|
||||||
for y := 0; y < int(items[ind].(*gachaItem).itemCount); y++ {
|
|
||||||
// items in storage don't get rarity
|
|
||||||
dbUpdate.WriteUint8(uint8(items[ind].(*gachaItem).itemType[y]))
|
|
||||||
dbUpdate.WriteUint16(uint16(items[ind].(*gachaItem).itemId[y]))
|
|
||||||
dbUpdate.WriteUint16(uint16(items[ind].(*gachaItem).quantity[y]))
|
|
||||||
data = append(data, dbUpdate.Data()...)
|
|
||||||
dbUpdate.Seek(0, 0)
|
|
||||||
// response needs all item info and the rarity
|
|
||||||
resp.WriteBytes(dbUpdate.Data())
|
|
||||||
resp.WriteUint8(items[ind].(*gachaItem).rarityIcon)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp.Seek(0, 0)
|
bf.WriteUint8(uint8(len(rewards)))
|
||||||
resp.WriteUint8(results)
|
bf.WriteBytes(temp.Data())
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
addGachaItem(s, rewards)
|
||||||
// add claimables to DB
|
|
||||||
data[0] = data[0] + results
|
|
||||||
_, err = s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", data, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update minidata in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
// deduct gacha coins if relevant, items are handled fine by the standard savedata packet immediately afterwards
|
|
||||||
if currType == 19 {
|
|
||||||
_, err = s.server.db.Exec("UPDATE characters SET gacha_trial = CASE WHEN (gacha_trial > $1) then gacha_trial - $1 else gacha_trial end, gacha_prem = CASE WHEN NOT (gacha_trial > $1) then gacha_prem - $1 else gacha_prem end WHERE id=$2", currNumber, s.charID)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_items in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
|
||||||
// should write to database when that's set up
|
pkt := p.(*mhfpacket.MsgMhfPlayStepupGacha)
|
||||||
pkt := p.(*mhfpacket.MsgMhfUseGachaPoint)
|
bf := byteframe.NewByteFrame()
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
var gachaEntries []GachaEntry
|
||||||
|
var entry GachaEntry
|
||||||
|
var rewards []GachaItem
|
||||||
|
var reward GachaItem
|
||||||
|
err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType)
|
||||||
|
if err != nil {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
temp := byteframe.NewByteFrame()
|
||||||
|
guaranteedItems := getGuaranteedItems(s, pkt.GachaID, pkt.RollType)
|
||||||
|
for _, item := range guaranteedItems {
|
||||||
|
temp.WriteUint8(item.ItemType)
|
||||||
|
temp.WriteUint16(item.ItemID)
|
||||||
|
temp.WriteUint16(item.Quantity)
|
||||||
|
temp.WriteUint8(0)
|
||||||
|
}
|
||||||
|
entries, 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 {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for entries.Next() {
|
||||||
|
entries.StructScan(&entry)
|
||||||
|
gachaEntries = append(gachaEntries, entry)
|
||||||
|
}
|
||||||
|
rewardEntries, err := getRandomEntries(gachaEntries, rolls, false)
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for items.Next() {
|
||||||
|
items.StructScan(&reward)
|
||||||
|
rewards = append(rewards, reward)
|
||||||
|
temp.WriteUint8(reward.ItemType)
|
||||||
|
temp.WriteUint16(reward.ItemID)
|
||||||
|
temp.WriteUint16(reward.Quantity)
|
||||||
|
temp.WriteUint8(entry.Rarity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bf.WriteUint8(uint8(len(rewards) + len(guaranteedItems)))
|
||||||
|
bf.WriteUint8(uint8(len(rewards)))
|
||||||
|
bf.WriteBytes(temp.Data())
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
addGachaItem(s, rewards)
|
||||||
|
addGachaItem(s, guaranteedItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfGetStepupStatus)
|
||||||
|
// TODO: Reset daily (noon)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
if stepCheck == 0 {
|
||||||
|
s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID)
|
||||||
|
step = 0
|
||||||
|
}
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
bf.WriteUint8(step)
|
||||||
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var entryIDs []uint32
|
||||||
|
for entries.Next() {
|
||||||
|
var entryID uint32
|
||||||
|
entries.Scan(&entryID)
|
||||||
|
entryIDs = append(entryIDs, entryID)
|
||||||
|
}
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
bf.WriteUint8(uint8(len(entryIDs)))
|
||||||
|
for i := range entryIDs {
|
||||||
|
bf.WriteUint32(entryIDs[i])
|
||||||
|
bf.WriteBool(true)
|
||||||
|
}
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfPlayBoxGacha)
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
var gachaEntries []GachaEntry
|
||||||
|
var entry GachaEntry
|
||||||
|
var rewards []GachaItem
|
||||||
|
var reward GachaItem
|
||||||
|
err, rolls := transactGacha(s, pkt.GachaID, pkt.RollType)
|
||||||
|
if err != nil {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
temp := byteframe.NewByteFrame()
|
||||||
|
entries, 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 {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for entries.Next() {
|
||||||
|
entries.StructScan(&entry)
|
||||||
|
gachaEntries = append(gachaEntries, entry)
|
||||||
|
}
|
||||||
|
rewardEntries, err := getRandomEntries(gachaEntries, rolls, true)
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
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)
|
||||||
|
for items.Next() {
|
||||||
|
items.StructScan(&reward)
|
||||||
|
rewards = append(rewards, reward)
|
||||||
|
temp.WriteUint8(reward.ItemType)
|
||||||
|
temp.WriteUint16(reward.ItemID)
|
||||||
|
temp.WriteUint16(reward.Quantity)
|
||||||
|
temp.WriteUint8(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bf.WriteUint8(uint8(len(rewards)))
|
||||||
|
bf.WriteBytes(temp.Data())
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
addGachaItem(s, rewards)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfResetBoxGachaInfo)
|
||||||
|
s.server.db.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)
|
s.server.db.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 characters SET frontier_points=frontier_points::int - $1 WHERE id=$2 RETURNING frontier_points", cost, s.charID).Scan(&balance)
|
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)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint32(balance)
|
bf.WriteUint32(balance)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
@@ -335,7 +611,7 @@ func handleMsgMhfExchangeItem2Fpoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
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)
|
s.server.db.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 characters SET frontier_points=COALESCE(frontier_points::int + $1, $1) WHERE id=$2 RETURNING frontier_points", cost, s.charID).Scan(&balance)
|
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)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint32(balance)
|
bf.WriteUint32(balance)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
@@ -394,291 +670,6 @@ func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfPlayStepupGacha)
|
|
||||||
results := byte(0)
|
|
||||||
stepResults := byte(0)
|
|
||||||
resp := byteframe.NewByteFrame()
|
|
||||||
rollFrame := byteframe.NewByteFrame()
|
|
||||||
stepFrame := byteframe.NewByteFrame()
|
|
||||||
stepData := []byte{}
|
|
||||||
var currType, rarityIcon, rollsCount, itemCount byte
|
|
||||||
var currQuant, currNumber, percentage uint16
|
|
||||||
var itemhash uint32
|
|
||||||
var itemType, itemId, quantity pq.Int64Array
|
|
||||||
var items []lottery.Weighter
|
|
||||||
// get info for updating data and calculating costs
|
|
||||||
err := s.server.db.QueryRow("SELECT currType, currNumber, currQuant, rollsCount, itemCount, itemType, itemId, quantity FROM gacha_shop_items WHERE shophash=$1 AND entryType=$2", pkt.GachaHash, pkt.RollType).Scan(&currType, &currNumber, &currQuant, &rollsCount, &itemCount, (*pq.Int64Array)(&itemType), (*pq.Int64Array)(&itemId), (*pq.Int64Array)(&quantity))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// get existing items in storage if any
|
|
||||||
var data []byte
|
|
||||||
_ = s.server.db.QueryRow("SELECT gacha_items FROM characters WHERE id = $1", s.charID).Scan(&data)
|
|
||||||
if len(data) == 0 {
|
|
||||||
data = []byte{0x00}
|
|
||||||
}
|
|
||||||
// roll definition includes items with step up gachas that are appended last
|
|
||||||
for x := 0; x < int(itemCount); x++ {
|
|
||||||
stepFrame.WriteUint8(uint8(itemType[x]))
|
|
||||||
stepFrame.WriteUint16(uint16(itemId[x]))
|
|
||||||
stepFrame.WriteUint16(uint16(quantity[x]))
|
|
||||||
stepData = append(stepData, stepFrame.Data()...)
|
|
||||||
stepFrame.WriteUint8(0) // rarity still defined
|
|
||||||
stepResults++
|
|
||||||
}
|
|
||||||
// get gacha items and iterate through them for gacha roll
|
|
||||||
shopEntries, err := s.server.db.Query("SELECT itemhash, percentage, rarityIcon, itemCount, itemType, itemId, quantity FROM gacha_shop_items WHERE shophash=$1 AND entryType=100", pkt.GachaHash)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for shopEntries.Next() {
|
|
||||||
err = shopEntries.Scan(&itemhash, &percentage, &rarityIcon, &itemCount, (*pq.Int64Array)(&itemType), (*pq.Int64Array)(&itemId), (*pq.Int64Array)(&quantity))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
items = append(items, &gachaItem{itemhash: itemhash, percentage: percentage, rarityIcon: rarityIcon, itemCount: itemCount, itemType: itemType, itemId: itemId, quantity: quantity})
|
|
||||||
}
|
|
||||||
// execute rolls, build response and update database
|
|
||||||
resp.WriteUint16(0) // results count goes here later
|
|
||||||
l := lottery.NewDefaultLottery()
|
|
||||||
for x := 0; x < int(rollsCount); x++ {
|
|
||||||
ind := l.Draw(items)
|
|
||||||
results += items[ind].(*gachaItem).itemCount
|
|
||||||
for y := 0; y < int(items[ind].(*gachaItem).itemCount); y++ {
|
|
||||||
// items in storage don't get rarity
|
|
||||||
rollFrame.WriteUint8(uint8(items[ind].(*gachaItem).itemType[y]))
|
|
||||||
rollFrame.WriteUint16(uint16(items[ind].(*gachaItem).itemId[y]))
|
|
||||||
rollFrame.WriteUint16(uint16(items[ind].(*gachaItem).quantity[y]))
|
|
||||||
data = append(data, rollFrame.Data()...)
|
|
||||||
rollFrame.Seek(0, 0)
|
|
||||||
// response needs all item info and the rarity
|
|
||||||
resp.WriteBytes(rollFrame.Data())
|
|
||||||
resp.WriteUint8(items[ind].(*gachaItem).rarityIcon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resp.WriteBytes(stepFrame.Data())
|
|
||||||
resp.Seek(0, 0)
|
|
||||||
resp.WriteUint8(results + stepResults)
|
|
||||||
resp.WriteUint8(results)
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
|
||||||
|
|
||||||
// add claimables to DB
|
|
||||||
data = append(data, stepData...)
|
|
||||||
data[0] = data[0] + results + stepResults
|
|
||||||
_, err = s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", data, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_items in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
// deduct gacha coins if relevant, items are handled fine by the standard savedata packet immediately afterwards
|
|
||||||
// reduce real if trial don't cover cost
|
|
||||||
if currType == 19 {
|
|
||||||
_, err = s.server.db.Exec(`UPDATE characters
|
|
||||||
SET gacha_trial = CASE WHEN (gacha_trial > $1) then gacha_trial - $1 else gacha_trial end,
|
|
||||||
gacha_prem = CASE WHEN NOT (gacha_trial > $1) then gacha_prem - $1 else gacha_prem end
|
|
||||||
WHERE id=$2`, currNumber, s.charID)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_items in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
// update step progression
|
|
||||||
_, err = s.server.db.Exec("UPDATE stepup_state SET step_progression = $1 WHERE char_id = $2", pkt.RollType+1, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update step_progression in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfReceiveGachaItem)
|
|
||||||
// persistent for claimable items on cat
|
|
||||||
var data []byte
|
|
||||||
err := s.server.db.QueryRow("SELECT COALESCE(gacha_items, $2) FROM characters WHERE id = $1", s.charID, []byte{0x00}).Scan(&data)
|
|
||||||
if err != nil {
|
|
||||||
panic("Failed to get gacha_items")
|
|
||||||
}
|
|
||||||
// limit of 36 items are returned
|
|
||||||
if data[0] > 36 {
|
|
||||||
outData := make([]byte, 181)
|
|
||||||
copy(outData, data[0:181])
|
|
||||||
outData[0] = byte(36)
|
|
||||||
saveData := append(data[:1], data[181:]...)
|
|
||||||
saveData[0] = saveData[0] - 36
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, outData)
|
|
||||||
if pkt.Unk0 != 0x2401 {
|
|
||||||
_, err := s.server.db.Exec("UPDATE characters SET gacha_items = $2 WHERE id = $1", s.charID, saveData)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_items in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
|
||||||
if pkt.Unk0 != 0x2401 {
|
|
||||||
_, err := s.server.db.Exec("UPDATE characters SET gacha_items = null WHERE id = $1", s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_items in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetStepupStatus)
|
|
||||||
// get the reset time from db
|
|
||||||
var step_progression int
|
|
||||||
var step_time time.Time
|
|
||||||
err := s.server.db.QueryRow(`SELECT COALESCE(step_progression, 0), COALESCE(step_time, $1) FROM stepup_state WHERE char_id = $2 AND shophash = $3`, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), s.charID, pkt.GachaHash).Scan(&step_progression, &step_time)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to Select coalesce in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate next midday
|
|
||||||
var t = time.Now().In(time.FixedZone("UTC+9", 9*60*60))
|
|
||||||
year, month, day := t.Date()
|
|
||||||
midday := time.Date(year, month, day, 12, 0, 0, 0, t.Location())
|
|
||||||
if t.After(midday) {
|
|
||||||
midday = midday.Add(24 * time.Hour)
|
|
||||||
}
|
|
||||||
// after midday or not set
|
|
||||||
if t.After(step_time) {
|
|
||||||
step_progression = 0
|
|
||||||
}
|
|
||||||
_, err = s.server.db.Exec(`INSERT INTO stepup_state (shophash, step_progression, step_time, char_id)
|
|
||||||
VALUES ($1,$2,$3,$4) ON CONFLICT (shophash, char_id)
|
|
||||||
DO UPDATE SET step_progression=$2, step_time=$3
|
|
||||||
WHERE EXCLUDED.char_id=$4 AND EXCLUDED.shophash=$1`, pkt.GachaHash, step_progression, midday, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update platedata savedata in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
resp := byteframe.NewByteFrame()
|
|
||||||
resp.WriteUint8(uint8(step_progression))
|
|
||||||
resp.WriteUint32(uint32(time.Now().In(time.FixedZone("UTC+9", 9*60*60)).Unix()))
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfPlayFreeGacha(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfPlayFreeGacha(s *Session, p mhfpacket.MHFPacket) {
|
||||||
// not sure this is used anywhere, free gachas use the MSG_MHF_PLAY_NORMAL_GACHA method in captures
|
// not sure this is used anywhere, free gachas use the MSG_MHF_PLAY_NORMAL_GACHA method in captures
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetBoxGachaInfo)
|
|
||||||
count := 0
|
|
||||||
var used_itemhash pq.Int64Array
|
|
||||||
// pull array of used values
|
|
||||||
// single sized respone with 0x00 is a valid with no items present
|
|
||||||
_ = s.server.db.QueryRow("SELECT used_itemhash FROM lucky_box_state WHERE shophash=$1 AND char_id=$2", pkt.GachaHash, s.charID).Scan((*pq.Int64Array)(&used_itemhash))
|
|
||||||
resp := byteframe.NewByteFrame()
|
|
||||||
resp.WriteUint8(0)
|
|
||||||
for ind := range used_itemhash {
|
|
||||||
resp.WriteUint32(uint32(used_itemhash[ind]))
|
|
||||||
resp.WriteUint8(1)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
resp.Seek(0, 0)
|
|
||||||
resp.WriteUint8(uint8(count))
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfPlayBoxGacha)
|
|
||||||
// needs to query db for input gacha and return a result or number of results
|
|
||||||
// uint8 number of results
|
|
||||||
// uint8 item type
|
|
||||||
// uint16 item id
|
|
||||||
// uint16 quantity
|
|
||||||
|
|
||||||
var currType, rarityIcon, rollsCount, itemCount byte
|
|
||||||
var currQuant, currNumber, percentage uint16
|
|
||||||
var itemhash uint32
|
|
||||||
var itemType, itemId, quantity, usedItemHash pq.Int64Array
|
|
||||||
var items []lottery.Weighter
|
|
||||||
// get info for updating data and calculating costs
|
|
||||||
err := s.server.db.QueryRow("SELECT currType, currNumber, currQuant, rollsCount FROM gacha_shop_items WHERE shophash=$1 AND entryType=$2", pkt.GachaHash, pkt.RollType).Scan(&currType, &currNumber, &currQuant, &rollsCount)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// get existing items in storage if any
|
|
||||||
var data []byte
|
|
||||||
_ = s.server.db.QueryRow("SELECT gacha_items FROM characters WHERE id = $1", s.charID).Scan(&data)
|
|
||||||
if len(data) == 0 {
|
|
||||||
data = []byte{0x00}
|
|
||||||
}
|
|
||||||
// get gacha items and iterate through them for gacha roll
|
|
||||||
shopEntries, err := s.server.db.Query(`SELECT itemhash, percentage, rarityIcon, itemCount, itemType, itemId, quantity
|
|
||||||
FROM gacha_shop_items
|
|
||||||
WHERE shophash=$1 AND entryType=100
|
|
||||||
EXCEPT ALL SELECT itemhash, percentage, rarityIcon, itemCount, itemType, itemId, quantity
|
|
||||||
FROM gacha_shop_items gsi JOIN lucky_box_state lbs ON gsi.itemhash = ANY(lbs.used_itemhash)
|
|
||||||
WHERE lbs.char_id=$2`, pkt.GachaHash, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for shopEntries.Next() {
|
|
||||||
err = shopEntries.Scan(&itemhash, &percentage, &rarityIcon, &itemCount, (*pq.Int64Array)(&itemType), (*pq.Int64Array)(&itemId), (*pq.Int64Array)(&quantity))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
items = append(items, &gachaItem{itemhash: itemhash, percentage: percentage, rarityIcon: rarityIcon, itemCount: itemCount, itemType: itemType, itemId: itemId, quantity: quantity})
|
|
||||||
}
|
|
||||||
// execute rolls, build response and update database
|
|
||||||
results := byte(0)
|
|
||||||
resp := byteframe.NewByteFrame()
|
|
||||||
dbUpdate := byteframe.NewByteFrame()
|
|
||||||
resp.WriteUint8(0) // results go here later
|
|
||||||
l := lottery.NewDefaultLottery()
|
|
||||||
for x := 0; x < int(rollsCount); x++ {
|
|
||||||
ind := l.Draw(items)
|
|
||||||
results += items[ind].(*gachaItem).itemCount
|
|
||||||
for y := 0; y < int(items[ind].(*gachaItem).itemCount); y++ {
|
|
||||||
// items in storage don't get rarity
|
|
||||||
dbUpdate.WriteUint8(uint8(items[ind].(*gachaItem).itemType[y]))
|
|
||||||
dbUpdate.WriteUint16(uint16(items[ind].(*gachaItem).itemId[y]))
|
|
||||||
dbUpdate.WriteUint16(uint16(items[ind].(*gachaItem).quantity[y]))
|
|
||||||
data = append(data, dbUpdate.Data()...)
|
|
||||||
dbUpdate.Seek(0, 0)
|
|
||||||
// response needs all item info and the rarity
|
|
||||||
resp.WriteBytes(dbUpdate.Data())
|
|
||||||
resp.WriteUint8(items[ind].(*gachaItem).rarityIcon)
|
|
||||||
|
|
||||||
usedItemHash = append(usedItemHash, int64(items[ind].(*gachaItem).itemhash))
|
|
||||||
}
|
|
||||||
// remove rolled
|
|
||||||
items = append(items[:ind], items[ind+1:]...)
|
|
||||||
}
|
|
||||||
resp.Seek(0, 0)
|
|
||||||
resp.WriteUint8(results)
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
|
||||||
|
|
||||||
// add claimables to DB
|
|
||||||
data[0] = data[0] + results
|
|
||||||
_, err = s.server.db.Exec("UPDATE characters SET gacha_items = $1 WHERE id = $2", data, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_items in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
// update lucky_box_state
|
|
||||||
_, err = s.server.db.Exec(`INSERT INTO lucky_box_state (char_id, shophash, used_itemhash)
|
|
||||||
VALUES ($1,$2,$3) ON CONFLICT (char_id, shophash)
|
|
||||||
DO UPDATE SET used_itemhash = COALESCE(lucky_box_state.used_itemhash::int[] || $3::int[], $3::int[])
|
|
||||||
WHERE EXCLUDED.char_id=$1 AND EXCLUDED.shophash=$2`, s.charID, pkt.GachaHash, usedItemHash)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update lucky box state in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
// deduct gacha coins if relevant, items are handled fine by the standard savedata packet immediately afterwards
|
|
||||||
if currType == 19 {
|
|
||||||
_, err = s.server.db.Exec(`UPDATE characters
|
|
||||||
SET gacha_trial = CASE WHEN (gacha_trial > $1) then gacha_trial - $1 else gacha_trial end, gacha_prem = CASE WHEN NOT (gacha_trial > $1) then gacha_prem - $1 else gacha_prem end
|
|
||||||
WHERE id=$2`, currNumber, s.charID)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gacha_trial in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
|
|
||||||
pkt := p.(*mhfpacket.MsgMhfResetBoxGachaInfo)
|
|
||||||
_, err := s.server.db.Exec("DELETE FROM lucky_box_state WHERE shophash=$1 AND char_id=$2", pkt.GachaHash, s.charID)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
switch pkt.Unk0 {
|
switch pkt.Unk0 {
|
||||||
case 0:
|
case 0:
|
||||||
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix()))
|
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||||
bf.WriteUint32(0) // Tied to schedule ID?
|
bf.WriteUint32(0) // Tied to schedule ID?
|
||||||
case 1:
|
case 1:
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,42 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
// if the game gets bad responses for this it breaks the ability to save
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfGetTenrouirai)
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
if pkt.Unk0 == 1 {
|
||||||
|
data, err = hex.DecodeString("0A218EAD000000000000000000000001010000000000060010")
|
||||||
|
} else if pkt.Unk2 == 4 {
|
||||||
|
data, err = hex.DecodeString("0A218EAD0000000000000000000000210101005000000202010102020104001000000202010102020106003200000202010002020104000C003202020101020201030032000002020101020202059C4000000202010002020105C35000320202010102020201003C00000202010102020203003200000201010001020203002800320201010101020204000C00000201010101020206002800000201010001020101003C00320201020101020105C35000000301020101020106003200000301020001020104001000320301020101020105C350000003010201010202030028000003010200010201030032003203010201010202059C4000000301020101010206002800000301020001010201003C00320301020101010206003200000301020101010204000C000003010200010101010050003203010201010101059C40000003010201010101030032000003010200010101040010003203010001010101060032000003010001010102030028000003010001010101010050003203010000010102059C4000000301000001010206002800000301000001010010")
|
||||||
|
} else {
|
||||||
|
data = []byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
s.logger.Info("GET_TENROUIRAI request for unknown type")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfPostTenrouirai)
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
|
|
||||||
|
func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfGetWeeklySeibatuRankingReward)
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
pkt := p.(*mhfpacket.MsgMhfPresentBox)
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetGemInfo)
|
pkt := p.(*mhfpacket.MsgMhfGetGemInfo)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
|
|||||||
cryptConn: network.NewCryptConn(conn),
|
cryptConn: network.NewCryptConn(conn),
|
||||||
sendPackets: make(chan packet, 20),
|
sendPackets: make(chan packet, 20),
|
||||||
clientContext: &clientctx.ClientContext{}, // Unused
|
clientContext: &clientctx.ClientContext{}, // Unused
|
||||||
sessionStart: Time_Current_Adjusted().Unix(),
|
sessionStart: TimeAdjusted().Unix(),
|
||||||
stageMoveStack: stringstack.New(),
|
stageMoveStack: stringstack.New(),
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"erupe-ce/config"
|
"erupe-ce/config"
|
||||||
@@ -112,7 +113,11 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) {
|
|||||||
|
|
||||||
s.logger.Debug("Got entrance server command:\n", zap.String("raw", hex.Dump(pkt)))
|
s.logger.Debug("Got entrance server command:\n", zap.String("raw", hex.Dump(pkt)))
|
||||||
|
|
||||||
data := makeSv2Resp(s.erupeConfig, s)
|
local := false
|
||||||
|
if strings.Split(conn.RemoteAddr().String(), ":")[0] == "127.0.0.1" {
|
||||||
|
local = true
|
||||||
|
}
|
||||||
|
data := makeSv2Resp(s.erupeConfig, s, local)
|
||||||
if len(pkt) > 5 {
|
if len(pkt) > 5 {
|
||||||
data = append(data, makeUsrResp(pkt, s)...)
|
data = append(data, makeUsrResp(pkt, s)...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ var season uint8
|
|||||||
// Server Channels
|
// Server Channels
|
||||||
var currentplayers uint16
|
var currentplayers uint16
|
||||||
|
|
||||||
func encodeServerInfo(config *config.Config, s *Server) []byte {
|
func encodeServerInfo(config *config.Config, s *Server, local bool) []byte {
|
||||||
serverInfos := config.Entrance.Entries
|
serverInfos := config.Entrance.Entries
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
@@ -30,7 +30,11 @@ func encodeServerInfo(config *config.Config, s *Server) []byte {
|
|||||||
if si.IP == "" {
|
if si.IP == "" {
|
||||||
si.IP = config.Host
|
si.IP = config.Host
|
||||||
}
|
}
|
||||||
bf.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(si.IP).To4()))
|
if local {
|
||||||
|
bf.WriteUint32(0x0100007F) // 127.0.0.1
|
||||||
|
} else {
|
||||||
|
bf.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(si.IP).To4()))
|
||||||
|
}
|
||||||
bf.WriteUint16(16 + uint16(serverIdx))
|
bf.WriteUint16(16 + uint16(serverIdx))
|
||||||
bf.WriteUint16(0x0000)
|
bf.WriteUint16(0x0000)
|
||||||
bf.WriteUint16(uint16(len(si.Channels)))
|
bf.WriteUint16(uint16(len(si.Channels)))
|
||||||
@@ -62,7 +66,7 @@ func encodeServerInfo(config *config.Config, s *Server) []byte {
|
|||||||
bf.WriteUint16(0x3039)
|
bf.WriteUint16(0x3039)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Unix()))
|
bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix()))
|
||||||
bf.WriteUint32(0x0000003C)
|
bf.WriteUint32(0x0000003C)
|
||||||
return bf.Data()
|
return bf.Data()
|
||||||
}
|
}
|
||||||
@@ -85,9 +89,9 @@ func makeHeader(data []byte, respType string, entryCount uint16, key byte) []byt
|
|||||||
return bf.Data()
|
return bf.Data()
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSv2Resp(config *config.Config, s *Server) []byte {
|
func makeSv2Resp(config *config.Config, s *Server, local bool) []byte {
|
||||||
serverInfos := config.Entrance.Entries
|
serverInfos := config.Entrance.Entries
|
||||||
rawServerData := encodeServerInfo(config, s)
|
rawServerData := encodeServerInfo(config, s, local)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteBytes(makeHeader(rawServerData, "SV2", uint16(len(serverInfos)), 0x00))
|
bf.WriteBytes(makeHeader(rawServerData, "SV2", uint16(len(serverInfos)), 0x00))
|
||||||
return bf.Data()
|
return bf.Data()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"erupe-ce/server/channelserver"
|
"erupe-ce/server/channelserver"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -51,7 +52,11 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
|||||||
ps.Uint8(bf, s.server.erupeConfig.PatchServerFile, false)
|
ps.Uint8(bf, s.server.erupeConfig.PatchServerFile, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false)
|
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)
|
||||||
|
} else {
|
||||||
|
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false)
|
||||||
|
}
|
||||||
|
|
||||||
lastPlayed := uint32(0)
|
lastPlayed := uint32(0)
|
||||||
for _, char := range chars {
|
for _, char := range chars {
|
||||||
@@ -122,12 +127,7 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
|||||||
bf.WriteUint16(0x0001)
|
bf.WriteUint16(0x0001)
|
||||||
bf.WriteUint16(0x4E20)
|
bf.WriteUint16(0x4E20)
|
||||||
ps.Uint16(bf, "", false) // unk ipv4
|
ps.Uint16(bf, "", false) // unk ipv4
|
||||||
if returnExpiry.Before(time.Now()) {
|
bf.WriteUint32(uint32(returnExpiry.Unix()))
|
||||||
// Hack to make Return work while having a non-adjusted expiry
|
|
||||||
bf.WriteUint32(0)
|
|
||||||
} else {
|
|
||||||
bf.WriteUint32(uint32(returnExpiry.Unix()))
|
|
||||||
}
|
|
||||||
bf.WriteUint32(0x00000000)
|
bf.WriteUint32(0x00000000)
|
||||||
bf.WriteUint32(0x0A5197DF) // unk id
|
bf.WriteUint32(0x0A5197DF) // unk id
|
||||||
|
|
||||||
@@ -135,9 +135,9 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
|||||||
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt
|
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt
|
||||||
if mezfes {
|
if mezfes {
|
||||||
// Start time
|
// Start time
|
||||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
|
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
|
||||||
// End time
|
// 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.WriteUint8(2) // Unk
|
||||||
bf.WriteUint32(20) // Single tickets
|
bf.WriteUint32(20) // Single tickets
|
||||||
bf.WriteUint32(10) // Group tickets
|
bf.WriteUint32(10) // Group tickets
|
||||||
|
|||||||
Reference in New Issue
Block a user