Merge branch 'main' into feature/systems-rework

This commit is contained in:
wish
2022-09-30 03:33:56 +10:00
7 changed files with 390 additions and 247 deletions

View File

@@ -29,6 +29,25 @@
"bottoken": "",
"realtimeChannelID": ""
},
"Commands": [
{
"name": "Rights",
"enabled": true,
"prefix": "!rights"
}, {
"name": "Raviente",
"enabled": true,
"prefix": "!ravi"
}, {
"name": "Teleport",
"enabled": true,
"prefix": "!tele"
}, {
"name": "Reload",
"enabled": true,
"prefix": "!reload"
}
],
"database": {
"host": "localhost",
"port": 5432,
@@ -37,13 +56,19 @@
"database": "erupe"
},
"launcher": {
"enabled": true,
"port": 80,
"UseOriginalLauncherFiles": false
},
"sign": {
"enabled": true,
"port": 53312
},
"channel": {
"enabled": true
},
"entrance": {
"enabled": true,
"port": 53310,
"entries": [
{

View File

@@ -1,8 +1,11 @@
package config
import (
"fmt"
"log"
"net"
"os"
"time"
"github.com/spf13/viper"
)
@@ -16,9 +19,11 @@ type Config struct {
DevModeOptions DevModeOptions
Discord Discord
Commands []Command
Database Database
Launcher Launcher
Sign Sign
Channel Channel
Entrance Entrance
}
@@ -54,6 +59,13 @@ type Discord struct {
RealtimeChannelID string
}
// Command is a channelserver chat command
type Command struct {
Name string
Enabled bool
Prefix string
}
// Database holds the postgres database config.
type Database struct {
Host string
@@ -65,17 +77,24 @@ type Database struct {
// Launcher holds the launcher server config.
type Launcher struct {
Enabled bool
Port int
UseOriginalLauncherFiles bool
}
// Sign holds the sign server config.
type Sign struct {
Port int
Enabled bool
Port int
}
type Channel struct {
Enabled bool
}
// Entrance holds the entrance server config.
type Entrance struct {
Enabled bool
Port uint16
Entries []EntranceServerInfo
}
@@ -102,6 +121,17 @@ type EntranceChannelInfo struct {
CurrentPlayers uint16
}
var ErupeConfig *Config
func init() {
var err error
ErupeConfig, err = LoadConfig()
if err != nil {
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
}
}
// getOutboundIP4 gets the preferred outbound ip4 of this machine
// From https://stackoverflow.com/a/37382208
func getOutboundIP4() net.IP {
@@ -143,3 +173,20 @@ func LoadConfig() (*Config, error) {
return c, nil
}
func preventClose(text string) {
if ErupeConfig.DisableSoftCrash {
os.Exit(0)
}
fmt.Println("\nFailed to start Erupe:\n" + text)
go wait()
fmt.Println("\nPress Enter/Return to exit...")
fmt.Scanln()
os.Exit(0)
}
func wait() {
for {
time.Sleep(time.Millisecond * 100)
}
}

2
go.mod
View File

@@ -19,5 +19,5 @@ require (
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.8 // indirect
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
)

22
go.sum
View File

@@ -78,9 +78,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -189,9 +188,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -202,9 +200,8 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -222,9 +219,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -295,6 +291,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -333,7 +330,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -508,8 +505,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
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.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -617,9 +614,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

185
main.go
View File

@@ -14,13 +14,12 @@ import (
"erupe-ce/server/entranceserver"
"erupe-ce/server/launcherserver"
"erupe-ce/server/signserver"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
var erupeConfig *config.Config
// Temporary DB auto clean on startup for quick development & testing.
func cleanDB(db *sqlx.DB) {
_ = db.MustExec("DELETE FROM guild_characters")
@@ -38,25 +37,19 @@ func main() {
logger.Info("Starting Erupe")
// Load the configuration.
erupeConfig, err = config.LoadConfig()
if err != nil {
preventClose(fmt.Sprintf("Failed to load config: %s", err.Error()))
}
if erupeConfig.Database.Password == "" {
if config.ErupeConfig.Database.Password == "" {
preventClose("Database password is blank")
}
if net.ParseIP(erupeConfig.Host) == nil {
ips, _ := net.LookupIP(erupeConfig.Host)
if net.ParseIP(config.ErupeConfig.Host) == nil {
ips, _ := net.LookupIP(config.ErupeConfig.Host)
for _, ip := range ips {
if ip != nil {
erupeConfig.Host = ip.String()
config.ErupeConfig.Host = ip.String()
break
}
}
if net.ParseIP(erupeConfig.Host) == nil {
if net.ParseIP(config.ErupeConfig.Host) == nil {
preventClose("Invalid host address")
}
}
@@ -64,10 +57,10 @@ func main() {
// Discord bot
var discordBot *discordbot.DiscordBot = nil
if erupeConfig.Discord.Enabled {
if config.ErupeConfig.Discord.Enabled {
bot, err := discordbot.NewDiscordBot(discordbot.Options{
Logger: logger,
Config: erupeConfig,
Config: config.ErupeConfig,
})
if err != nil {
@@ -90,11 +83,11 @@ func main() {
// Create the postgres DB pool.
connectString := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname= %s sslmode=disable",
erupeConfig.Database.Host,
erupeConfig.Database.Port,
erupeConfig.Database.User,
erupeConfig.Database.Password,
erupeConfig.Database.Database,
config.ErupeConfig.Database.Host,
config.ErupeConfig.Database.Port,
config.ErupeConfig.Database.User,
config.ErupeConfig.Database.Password,
config.ErupeConfig.Database.Database,
)
db, err := sqlx.Open("postgres", connectString)
@@ -116,7 +109,7 @@ func main() {
_ = db.MustExec("UPDATE characters SET cafe_time=0")
// Clean the DB if the option is on.
if erupeConfig.DevMode && erupeConfig.DevModeOptions.CleanDB {
if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB {
logger.Info("Cleaning DB")
cleanDB(db)
logger.Info("Done cleaning DB")
@@ -126,13 +119,13 @@ func main() {
// Launcher HTTP server.
var launcherServer *launcherserver.Server
if erupeConfig.DevMode && erupeConfig.DevModeOptions.EnableLauncherServer {
if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.EnableLauncherServer {
launcherServer = launcherserver.NewServer(
&launcherserver.Config{
Logger: logger.Named("launcher"),
ErupeConfig: erupeConfig,
ErupeConfig: config.ErupeConfig,
DB: db,
UseOriginalLauncherFiles: erupeConfig.Launcher.UseOriginalLauncherFiles,
UseOriginalLauncherFiles: config.ErupeConfig.Launcher.UseOriginalLauncherFiles,
})
err = launcherServer.Start()
if err != nil {
@@ -142,72 +135,83 @@ func main() {
}
// Entrance server.
entranceServer := entranceserver.NewServer(
&entranceserver.Config{
Logger: logger.Named("entrance"),
ErupeConfig: erupeConfig,
DB: db,
})
err = entranceServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error()))
var entranceServer *entranceserver.Server
if config.ErupeConfig.Entrance.Enabled {
entranceServer = entranceserver.NewServer(
&entranceserver.Config{
Logger: logger.Named("entrance"),
ErupeConfig: config.ErupeConfig,
DB: db,
})
err = entranceServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error()))
}
logger.Info("Started entrance server")
}
logger.Info("Started entrance server")
// Sign server.
signServer := signserver.NewServer(
&signserver.Config{
Logger: logger.Named("sign"),
ErupeConfig: erupeConfig,
DB: db,
})
err = signServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error()))
var signServer *signserver.Server
if config.ErupeConfig.Sign.Enabled {
signServer = signserver.NewServer(
&signserver.Config{
Logger: logger.Named("sign"),
ErupeConfig: config.ErupeConfig,
DB: db,
})
err = signServer.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error()))
}
logger.Info("Started sign server")
}
logger.Info("Started sign server")
var channels []*channelserver.Server
channelQuery := ""
si := 0
ci := 0
count := 1
for _, ee := range erupeConfig.Entrance.Entries {
for _, ce := range ee.Channels {
sid := (4096 + si*256) + (16 + ci)
c := *channelserver.NewServer(&channelserver.Config{
ID: uint16(sid),
Logger: logger.Named("channel-" + fmt.Sprint(count)),
ErupeConfig: erupeConfig,
DB: db,
DiscordBot: discordBot,
})
if ee.IP == "" {
c.IP = erupeConfig.Host
} else {
c.IP = ee.IP
}
c.Port = ce.Port
err = c.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error()))
} else {
channelQuery += fmt.Sprintf("INSERT INTO servers (server_id, season, current_players) VALUES (%d, %d, 0);", sid, si%3)
channels = append(channels, &c)
logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port))
ci++
count++
if config.ErupeConfig.Channel.Enabled {
channelQuery := ""
si := 0
ci := 0
count := 1
for _, ee := range config.ErupeConfig.Entrance.Entries {
for i, ce := range ee.Channels {
sid := (4096 + si*256) + (16 + ci)
c := *channelserver.NewServer(&channelserver.Config{
ID: uint16(sid),
Logger: logger.Named("channel-" + fmt.Sprint(count)),
ErupeConfig: config.ErupeConfig,
DB: db,
DiscordBot: discordBot,
})
if ee.IP == "" {
c.IP = config.ErupeConfig.Host
} else {
c.IP = ee.IP
}
c.Port = ce.Port
err = c.Start()
if err != nil {
preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error()))
} else {
channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, season, current_players, world_name, world_description, land) VALUES (%d, %d, 0, '%s', '%s', %d);`, sid, si%3, ee.Name, ee.Description, i+1)
channels = append(channels, &c)
logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port))
ci++
count++
}
}
ci = 0
si++
}
ci = 0
si++
}
// Register all servers in DB
_ = db.MustExec(channelQuery)
// Register all servers in DB
_ = db.MustExec(channelQuery)
for _, c := range channels {
c.Channels = channels
for _, c := range channels {
c.Channels = channels
}
}
// Wait for exit or interrupt with ctrl+C.
@@ -217,12 +221,21 @@ func main() {
logger.Info("Trying to shutdown gracefully")
for _, c := range channels {
c.Shutdown()
if config.ErupeConfig.Channel.Enabled {
for _, c := range channels {
c.Shutdown()
}
}
signServer.Shutdown()
entranceServer.Shutdown()
if erupeConfig.DevModeOptions.EnableLauncherServer {
if config.ErupeConfig.Sign.Enabled {
signServer.Shutdown()
}
if config.ErupeConfig.Entrance.Enabled {
entranceServer.Shutdown()
}
if config.ErupeConfig.DevModeOptions.EnableLauncherServer {
launcherServer.Shutdown()
}
@@ -236,7 +249,7 @@ func wait() {
}
func preventClose(text string) {
if erupeConfig.DisableSoftCrash {
if config.ErupeConfig.DisableSoftCrash {
os.Exit(0)
}
fmt.Println("\nFailed to start Erupe:\n" + text)

View File

@@ -0,0 +1,23 @@
--adds world_name and land columns
BEGIN;
CREATE TABLE IF NOT EXISTS public.servers
(
server_id integer NOT NULL,
season integer NOT NULL,
current_players integer NOT NULL,
world_name text COLLATE pg_catalog."default",
world_description text,
land integer
);
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS land integer;
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS world_name text COLLATE pg_catalog."default";
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS world_description text;
END;

View File

@@ -8,8 +8,11 @@ import (
"time"
"erupe-ce/common/byteframe"
"erupe-ce/config"
"erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
)
// MSG_SYS_CAST[ED]_BINARY types enum
@@ -29,6 +32,28 @@ const (
BroadcastTypeWorld = 0x0a
)
var commands map[string]config.Command
func init() {
commands = make(map[string]config.Command)
zapLogger, _ := zap.NewDevelopment()
defer zapLogger.Sync()
logger := zapLogger.Named("commands")
cmds := config.ErupeConfig.Commands
for _, cmd := range cmds {
commands[cmd.Name] = cmd
if cmd.Enabled {
logger.Info(fmt.Sprintf("%s command is enabled, prefix: %s", cmd.Name, cmd.Prefix))
} else {
logger.Info(fmt.Sprintf("%s command is disabled", cmd.Name))
}
}
}
func sendDisabledCommandMessage(s *Session, cmd config.Command) {
sendServerChatMessage(s, fmt.Sprintf("%s command is disabled", cmd.Name))
}
func sendServerChatMessage(s *Session, message string) {
// Make the inside of the casted binary
bf := byteframe.NewByteFrame()
@@ -165,167 +190,181 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
fmt.Printf("Got chat message: %+v\n", chatMessage)
// Flush all objects and users and reload
if strings.HasPrefix(chatMessage.Message, "!reload") {
sendServerChatMessage(s, "Reloading players...")
var temp mhfpacket.MHFPacket
deleteNotif := byteframe.NewByteFrame()
for _, object := range s.stage.objects {
if object.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
deleteNotif.WriteUint16(0x0010)
s.QueueSend(deleteNotif.Data())
time.Sleep(500 * time.Millisecond)
reloadNotif := byteframe.NewByteFrame()
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
}
for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDuplicateObject{
ObjID: obj.id,
X: obj.x,
Y: obj.y,
Z: obj.z,
Unk0: 0,
OwnerCharID: obj.ownerCharID,
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
reloadNotif.WriteUint16(0x0010)
s.QueueSend(reloadNotif.Data())
}
// Set account rights
if strings.HasPrefix(chatMessage.Message, "!rights") {
var v uint32
n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !rights n")
} else {
_, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v))
}
}
}
// Discord integration
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
}
// RAVI COMMANDS V2
if strings.HasPrefix(chatMessage.Message, "!ravi") {
if getRaviSemaphore(s) != "" {
s.server.raviente.Lock()
if !strings.HasPrefix(chatMessage.Message, "!ravi ") {
sendServerChatMessage(s, "No Raviente command specified!")
} else {
if strings.HasPrefix(chatMessage.Message, "!ravi start") {
if s.server.raviente.register.startTime == 0 {
s.server.raviente.register.startTime = s.server.raviente.register.postTime
sendServerChatMessage(s, "The Great Slaying will begin in a moment")
s.notifyRavi()
} else {
sendServerChatMessage(s, "The Great Slaying has already begun!")
if strings.HasPrefix(chatMessage.Message, commands["Reload"].Prefix) {
// Flush all objects and users and reload
if commands["Reload"].Enabled {
sendServerChatMessage(s, "Reloading players...")
var temp mhfpacket.MHFPacket
deleteNotif := byteframe.NewByteFrame()
for _, object := range s.stage.objects {
if object.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
deleteNotif.WriteUint16(0x0010)
s.QueueSend(deleteNotif.Data())
time.Sleep(500 * time.Millisecond)
reloadNotif := byteframe.NewByteFrame()
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi sm") || strings.HasPrefix(chatMessage.Message, "!ravi setmultiplier") {
var num uint16
n, numerr := fmt.Sscanf(chatMessage.Message, "!ravi sm %d", &num)
if numerr != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !ravi sm n")
} else if s.server.raviente.state.damageMultiplier == 1 {
if num > 32 {
sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x")
s.server.raviente.state.damageMultiplier = 32
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier set to %dx", num))
s.server.raviente.state.damageMultiplier = uint32(num)
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is already set to %dx!", s.server.raviente.state.damageMultiplier))
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi cm") || strings.HasPrefix(chatMessage.Message, "!ravi checkmultiplier") {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is currently %dx", s.server.raviente.state.damageMultiplier))
} else if strings.HasPrefix(chatMessage.Message, "!ravi sr") || strings.HasPrefix(chatMessage.Message, "!ravi sendres") {
if s.server.raviente.state.stateData[28] > 0 {
sendServerChatMessage(s, "Sending resurrection support!")
s.server.raviente.state.stateData[28] = 0
} else {
sendServerChatMessage(s, "Resurrection support has not been requested!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi ss") || strings.HasPrefix(chatMessage.Message, "!ravi sendsed") {
sendServerChatMessage(s, "Sending sedation support if requested!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP
} else if strings.HasPrefix(chatMessage.Message, "!ravi rs") || strings.HasPrefix(chatMessage.Message, "!ravi reqsed") {
sendServerChatMessage(s, "Requesting sedation support!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP + 12
} else {
sendServerChatMessage(s, "Raviente command not recognised!")
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
}
s.server.raviente.Unlock()
for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDuplicateObject{
ObjID: obj.id,
X: obj.x,
Y: obj.y,
Z: obj.z,
Unk0: 0,
OwnerCharID: obj.ownerCharID,
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
reloadNotif.WriteUint16(0x0010)
s.QueueSend(reloadNotif.Data())
} else {
sendServerChatMessage(s, "No one has joined the Great Slaying!")
sendDisabledCommandMessage(s, commands["Reload"])
}
}
// END RAVI COMMANDS V2
if strings.HasPrefix(chatMessage.Message, "!tele ") {
var x, y int16
n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y)
if err != nil || n != 2 {
sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"")
if strings.HasPrefix(chatMessage.Message, commands["Rights"].Prefix) {
// Set account rights
if commands["Rights"].Enabled {
var v uint32
n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !rights n")
} else {
_, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v))
}
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y))
sendDisabledCommandMessage(s, commands["Rights"])
}
}
// Make the inside of the casted binary
payload := byteframe.NewByteFrame()
payload.SetLE()
payload.WriteUint8(2) // SetState type(position == 2)
payload.WriteInt16(x) // X
payload.WriteInt16(y) // Y
payloadBytes := payload.Data()
if strings.HasPrefix(chatMessage.Message, commands["Raviente"].Prefix) {
if commands["Raviente"].Enabled {
if getRaviSemaphore(s) != "" {
s.server.raviente.Lock()
if !strings.HasPrefix(chatMessage.Message, "!ravi ") {
sendServerChatMessage(s, "No Raviente command specified!")
} else {
if strings.HasPrefix(chatMessage.Message, "!ravi start") {
if s.server.raviente.register.startTime == 0 {
s.server.raviente.register.startTime = s.server.raviente.register.postTime
sendServerChatMessage(s, "The Great Slaying will begin in a moment")
s.notifyRavi()
} else {
sendServerChatMessage(s, "The Great Slaying has already begun!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi sm") || strings.HasPrefix(chatMessage.Message, "!ravi setmultiplier") {
var num uint16
n, numerr := fmt.Sscanf(chatMessage.Message, "!ravi sm %d", &num)
if numerr != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !ravi sm n")
} else if s.server.raviente.state.damageMultiplier == 1 {
if num > 32 {
sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x")
s.server.raviente.state.damageMultiplier = 32
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier set to %dx", num))
s.server.raviente.state.damageMultiplier = uint32(num)
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is already set to %dx!", s.server.raviente.state.damageMultiplier))
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi cm") || strings.HasPrefix(chatMessage.Message, "!ravi checkmultiplier") {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is currently %dx", s.server.raviente.state.damageMultiplier))
} else if strings.HasPrefix(chatMessage.Message, "!ravi sr") || strings.HasPrefix(chatMessage.Message, "!ravi sendres") {
if s.server.raviente.state.stateData[28] > 0 {
sendServerChatMessage(s, "Sending resurrection support!")
s.server.raviente.state.stateData[28] = 0
} else {
sendServerChatMessage(s, "Resurrection support has not been requested!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi ss") || strings.HasPrefix(chatMessage.Message, "!ravi sendsed") {
sendServerChatMessage(s, "Sending sedation support if requested!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP
} else if strings.HasPrefix(chatMessage.Message, "!ravi rs") || strings.HasPrefix(chatMessage.Message, "!ravi reqsed") {
sendServerChatMessage(s, "Requesting sedation support!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP + 12
} else {
sendServerChatMessage(s, "Raviente command not recognised!")
}
}
s.server.raviente.Unlock()
} else {
sendServerChatMessage(s, "No one has joined the Great Slaying!")
}
} else {
sendDisabledCommandMessage(s, commands["Raviente"])
}
}
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes,
})
if strings.HasPrefix(chatMessage.Message, commands["Teleport"].Prefix) {
if commands["Teleport"].Enabled {
var x, y int16
n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y)
if err != nil || n != 2 {
sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"")
} else {
sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y))
// Make the inside of the casted binary
payload := byteframe.NewByteFrame()
payload.SetLE()
payload.WriteUint8(2) // SetState type(position == 2)
payload.WriteInt16(x) // X
payload.WriteInt16(y) // Y
payloadBytes := payload.Data()
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes,
})
}
} else {
sendDisabledCommandMessage(s, commands["Teleport"])
}
}
}