diff --git a/bundled-schema/NetcafeDefaults.sql b/bundled-schema/NetcafeDefaults.sql
new file mode 100644
index 000000000..458cfa7b9
--- /dev/null
+++ b/bundled-schema/NetcafeDefaults.sql
@@ -0,0 +1,13 @@
+BEGIN;
+
+INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity)
+VALUES
+ (1800, 17, 0, 250),
+ (3600, 17, 0, 500),
+ (7200, 17, 0, 1000),
+ (10800, 17, 0, 1500),
+ (18000, 17, 0, 1750),
+ (28800, 17, 0, 3000),
+ (43200, 17, 0, 4000);
+
+END;
\ No newline at end of file
diff --git a/config.json b/config.json
index ba9af8b77..31ecd8416 100644
--- a/config.json
+++ b/config.json
@@ -2,13 +2,17 @@
"Host": "127.0.0.1",
"BinPath": "bin",
"DisableSoftCrash": false,
- "devmode": true,
- "devmodeoptions": {
+ "FeaturedWeapons": 1,
+ "DevMode": true,
+ "DevModeOptions": {
+ "PatchServerManifest": "",
+ "PatchServerFile": "",
+ "AutoCreateAccount": true,
"EnableLauncherServer": false,
- "hideLoginNotice": false,
- "loginNotice": "
Welcome to Erupe SU9.1 Beta!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!
■Report bugs on Discord!
■Test everything!
■Don't talk to softlocking NPCs!
■Fork the code on GitHub!
Thank you to all of the contributors,
this wouldn't exist without you.",
- "cleandb": false,
- "maxlauncherhr": false,
+ "HideLoginNotice": false,
+ "LoginNotice": "Welcome to Erupe SU9.1 Beta!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!
■Report bugs on Discord!
■Test everything!
■Don't talk to softlocking NPCs!
■Fork the code on GitHub!
Thank you to all of the contributors,
this wouldn't exist without you.",
+ "CleanDB": false,
+ "MaxLauncherHR": false,
"LogInboundMessages": false,
"LogOutboundMessages": false,
"MaxHexdumpLength": 256,
@@ -19,93 +23,108 @@
"MezFesAlt": false,
"DisableMailItems": true,
"DisableTokenCheck": false,
+ "QuestDebugTools": false,
"SaveDumps": {
"Enabled": true,
"OutputDir": "savedata"
}
},
- "discord": {
- "enabled": false,
- "bottoken": "",
- "realtimeChannelID": ""
+ "Discord": {
+ "Enabled": false,
+ "BotToken": "",
+ "RealtimeChannelID": ""
},
"Commands": [
{
- "name": "Rights",
- "enabled": true,
- "prefix": "!rights"
+ "Name": "Rights",
+ "Enabled": false,
+ "Prefix": "!rights"
}, {
- "name": "Raviente",
- "enabled": true,
- "prefix": "!ravi"
+ "Name": "Raviente",
+ "Enabled": true,
+ "Prefix": "!ravi"
}, {
- "name": "Teleport",
- "enabled": false,
- "prefix": "!tele"
+ "Name": "Teleport",
+ "Enabled": false,
+ "Prefix": "!tele"
}, {
- "name": "Reload",
- "enabled": true,
- "prefix": "!reload"
+ "Name": "Reload",
+ "Enabled": true,
+ "Prefix": "!reload"
}, {
- "name": "KeyQuest",
- "enabled": false,
- "prefix": "!kqf"
+ "Name": "KeyQuest",
+ "Enabled": false,
+ "Prefix": "!kqf"
+ }, {
+ "Name": "Course",
+ "Enabled": true,
+ "Prefix": "!course"
}
],
- "database": {
- "host": "localhost",
- "port": 5432,
- "user": "postgres",
- "password": "",
- "database": "erupe"
+ "Courses": [
+ {"Name": "HunterLife", "Enabled": true},
+ {"Name": "ExtraA", "Enabled": true},
+ {"Name": "Premium", "Enabled": true},
+ {"Name": "Assist", "Enabled": false},
+ {"Name": "Netcafe", "Enabled": false},
+ {"Name": "Hiden", "Enabled": false},
+ {"Name": "HunterSupport", "Enabled": false},
+ {"Name": "NetcafeBoost", "Enabled": false}
+ ],
+ "Database": {
+ "Host": "localhost",
+ "Port": 5432,
+ "User": "postgres",
+ "Password": "",
+ "Database": "erupe"
},
- "launcher": {
- "enabled": true,
- "port": 80,
+ "Launcher": {
+ "Enabled": false,
+ "Port": 80,
"UseOriginalLauncherFiles": false
},
- "sign": {
- "enabled": true,
- "port": 53312
+ "Sign": {
+ "Enabled": true,
+ "Port": 53312
},
- "channel": {
- "enabled": true
+ "Channel": {
+ "Enabled": true
},
- "entrance": {
- "enabled": true,
- "port": 53310,
- "entries": [
+ "Entrance": {
+ "Enabled": true,
+ "Port": 53310,
+ "Entries": [
{
- "name": "Newbie", "description": "", "ip": "", "type": 3, "recommended": 2, "allowedclientflags": 0,
- "channels": [
- { "port": 54001, "MaxPlayers": 100 },
- { "port": 54002, "MaxPlayers": 100 }
+ "Name": "Newbie", "Description": "", "IP": "", "Type": 3, "Recommended": 2, "AllowedClientFlags": 0,
+ "Channels": [
+ { "Port": 54001, "MaxPlayers": 100 },
+ { "Port": 54002, "MaxPlayers": 100 }
]
}, {
- "name": "Normal", "description": "", "ip": "", "type": 1, "recommended": 0, "allowedclientflags": 0,
- "channels": [
- { "port": 54003, "MaxPlayers": 100 },
- { "port": 54004, "MaxPlayers": 100 }
+ "Name": "Normal", "Description": "", "IP": "", "Type": 1, "Recommended": 0, "AllowedClientFlags": 0,
+ "Channels": [
+ { "Port": 54003, "MaxPlayers": 100 },
+ { "Port": 54004, "MaxPlayers": 100 }
]
}, {
- "name": "Cities", "description": "", "ip": "", "type": 2, "recommended": 0, "allowedclientflags": 0,
- "channels": [
- { "port": 54005, "MaxPlayers": 100 }
+ "Name": "Cities", "Description": "", "IP": "", "Type": 2, "Recommended": 0, "AllowedClientFlags": 0,
+ "Channels": [
+ { "Port": 54005, "MaxPlayers": 100 }
]
}, {
- "name": "Tavern", "description": "", "ip": "", "type": 4, "recommended": 0, "allowedclientflags": 0,
- "channels": [
- { "port": 54006, "MaxPlayers": 100 }
+ "Name": "Tavern", "Description": "", "IP": "", "Type": 4, "Recommended": 0, "AllowedClientFlags": 0,
+ "Channels": [
+ { "Port": 54006, "MaxPlayers": 100 }
]
}, {
- "name": "Return", "description": "", "ip": "", "type": 5, "recommended": 0, "allowedclientflags": 0,
- "channels": [
- { "port": 54007, "MaxPlayers": 100 }
+ "Name": "Return", "Description": "", "IP": "", "Type": 5, "Recommended": 0, "AllowedClientFlags": 0,
+ "Channels": [
+ { "Port": 54007, "MaxPlayers": 100 }
]
}, {
- "name": "MezFes", "description": "", "ip": "", "type": 6, "recommended": 6, "allowedclientflags": 0,
- "channels": [
- { "port": 54008, "MaxPlayers": 100 }
+ "Name": "MezFes", "Description": "", "IP": "", "Type": 6, "Recommended": 6, "AllowedClientFlags": 0,
+ "Channels": [
+ { "Port": 54008, "MaxPlayers": 100 }
]
}
]
diff --git a/config/config.go b/config/config.go
index c90550f53..d2804b9fc 100644
--- a/config/config.go
+++ b/config/config.go
@@ -15,11 +15,13 @@ type Config struct {
Host string `mapstructure:"Host"`
BinPath string `mapstructure:"BinPath"`
DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically
+ FeaturedWeapons int // Number of Active Feature weapons to generate daily
DevMode bool
DevModeOptions DevModeOptions
Discord Discord
Commands []Command
+ Courses []Course
Database Database
Launcher Launcher
Sign Sign
@@ -29,22 +31,25 @@ type Config struct {
// DevModeOptions holds various debug/temporary options for use while developing Erupe.
type DevModeOptions struct {
- EnableLauncherServer bool // Enables the launcher server to be served on port 80
- HideLoginNotice bool // Hide the Erupe notice on login
- LoginNotice string // MHFML string of the login notice displayed
- CleanDB bool // Automatically wipes the DB on server reset.
- MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds.
- LogInboundMessages bool // Log all messages sent to the server
- LogOutboundMessages bool // Log all messages sent to the clients
- MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
- DivaEvent int // Diva Defense event status
- FestaEvent int // Hunter's Festa event status
- TournamentEvent int // VS Tournament event status
- MezFesEvent bool // MezFes status
- MezFesAlt bool // Swaps out Volpakkun for Tokotoko
- DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
- DisableMailItems bool // Hack to prevent english versions of MHF from crashing
- SaveDumps SaveDumpOptions
+ PatchServerManifest string // Manifest patch server override
+ PatchServerFile string // File patch server override
+ AutoCreateAccount bool // Automatically create accounts if they don't exist
+ HideLoginNotice bool // Hide the Erupe notice on login
+ LoginNotice string // MHFML string of the login notice displayed
+ CleanDB bool // Automatically wipes the DB on server reset.
+ MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds.
+ LogInboundMessages bool // Log all messages sent to the server
+ LogOutboundMessages bool // Log all messages sent to the clients
+ MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
+ DivaEvent int // Diva Defense event status
+ FestaEvent int // Hunter's Festa event status
+ TournamentEvent int // VS Tournament event status
+ MezFesEvent bool // MezFes status
+ MezFesAlt bool // Swaps out Volpakkun for Tokotoko
+ DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
+ DisableMailItems bool // Hack to prevent english versions of MHF from crashing
+ QuestDebugTools bool // Enable various quest debug logs
+ SaveDumps SaveDumpOptions
}
type SaveDumpOptions struct {
@@ -66,6 +71,12 @@ type Command struct {
Prefix string
}
+// Course represents a course within MHF
+type Course struct {
+ Name string
+ Enabled bool
+}
+
// Database holds the postgres database config.
type Database struct {
Host string
diff --git a/go.mod b/go.mod
index f4e7f1033..1d7f83e7b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,23 +1,38 @@
module erupe-ce
-go 1.16
+go 1.19
require (
github.com/bwmarrin/discordgo v0.23.2
- github.com/golang/mock v1.6.0 // indirect
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
- github.com/gorilla/websocket v1.4.2 // indirect
github.com/jmoiron/sqlx v1.3.4
github.com/lib/pq v1.10.4
- github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96
github.com/spf13/viper v1.8.1
+ go.uber.org/zap v1.18.1
+ golang.org/x/crypto v0.1.0
+ golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
+ golang.org/x/text v0.4.0
+)
+
+require (
+ github.com/felixge/httpsnoop v1.0.1 // indirect
+ github.com/fsnotify/fsnotify v1.4.9 // indirect
+ github.com/golang/mock v1.6.0 // indirect
+ github.com/gorilla/websocket v1.4.2 // indirect
+ github.com/hashicorp/hcl v1.0.0 // indirect
+ github.com/magiconair/properties v1.8.5 // indirect
+ github.com/mitchellh/mapstructure v1.4.3 // indirect
+ github.com/pelletier/go-toml v1.9.3 // indirect
+ github.com/spf13/afero v1.6.0 // indirect
+ github.com/spf13/cast v1.3.1 // indirect
+ github.com/spf13/jwalterweatherman v1.1.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/subosito/gotenv v1.2.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
- go.uber.org/zap v1.18.1
- golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
- golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
- golang.org/x/text v0.3.7
- golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
+ golang.org/x/sys v0.1.0 // indirect
+ gopkg.in/ini.v1 v1.62.0 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/go.sum b/go.sum
index 1e7747306..ca2bd44a9 100644
--- a/go.sum
+++ b/go.sum
@@ -261,7 +261,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
@@ -291,9 +290,8 @@ 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/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -304,6 +302,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc=
+golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -330,7 +330,6 @@ 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.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=
@@ -367,8 +366,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -432,12 +429,9 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/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-20210423082822-04245dca01da/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
-golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -446,9 +440,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -505,8 +498,7 @@ 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.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=
-golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
+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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/main.go b/main.go
index 3964ff315..dcb3a14b4 100644
--- a/main.go
+++ b/main.go
@@ -105,8 +105,6 @@ func main() {
// Clear stale data
_ = db.MustExec("DELETE FROM sign_sessions")
_ = db.MustExec("DELETE FROM servers")
- _ = db.MustExec("DELETE FROM cafe_accepted")
- _ = db.MustExec("UPDATE characters SET cafe_time=0")
// Clean the DB if the option is on.
if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB {
@@ -119,7 +117,7 @@ func main() {
// Launcher HTTP server.
var launcherServer *launcherserver.Server
- if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.EnableLauncherServer {
+ if config.ErupeConfig.Launcher.Enabled {
launcherServer = launcherserver.NewServer(
&launcherserver.Config{
Logger: logger.Named("launcher"),
@@ -235,7 +233,7 @@ func main() {
entranceServer.Shutdown()
}
- if config.ErupeConfig.DevModeOptions.EnableLauncherServer {
+ if config.ErupeConfig.Launcher.Enabled {
launcherServer.Shutdown()
}
diff --git a/migrations/000001_initial_db.down.sql b/migrations/000001_initial_db.down.sql
deleted file mode 100644
index 04f7e46f8..000000000
--- a/migrations/000001_initial_db.down.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN;
-
-DROP TABLE IF EXISTS sign_sessions;
-DROP TABLE IF EXISTS characters;
-DROP TABLE IF EXISTS users;
-
-DROP DOMAIN IF EXISTS uint8;
-DROP DOMAIN IF EXISTS uint16;
-
-END;
\ No newline at end of file
diff --git a/migrations/000001_initial_db.up.sql b/migrations/000001_initial_db.up.sql
deleted file mode 100644
index eeac64a33..000000000
--- a/migrations/000001_initial_db.up.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-BEGIN;
-
-CREATE DOMAIN uint8 AS smallint
- CHECK(VALUE >= 0 AND VALUE <= 255);
-
-CREATE DOMAIN uint16 AS integer
- CHECK(VALUE >= 0 AND VALUE <= 65536);
-
-CREATE TABLE users (
- id serial NOT NULL PRIMARY KEY,
- username text UNIQUE NOT NULL,
- password text NOT NULL,
- item_box bytea
-);
-
-CREATE TABLE characters (
- id serial NOT NULL PRIMARY KEY,
- user_id bigint REFERENCES users(id),
- is_female boolean,
- is_new_character boolean,
- small_gr_level uint8,
- gr_override_mode boolean,
- name varchar(15),
- unk_desc_string varchar(31),
- gr_override_level uint16,
- gr_override_unk0 uint8,
- gr_override_unk1 uint8
-);
-
-CREATE TABLE sign_sessions (
- id serial NOT NULL PRIMARY KEY,
- user_id bigint REFERENCES users(id),
- auth_token_num bigint,
- auth_token_str text
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000002_alter_characters.down.sql b/migrations/000002_alter_characters.down.sql
deleted file mode 100644
index c5eeb425b..000000000
--- a/migrations/000002_alter_characters.down.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- DROP COLUMN exp,
- DROP COLUMN weapon,
- DROP COLUMN last_login;
-
-END;
\ No newline at end of file
diff --git a/migrations/000002_alter_characters.up.sql b/migrations/000002_alter_characters.up.sql
deleted file mode 100644
index 8e92154dc..000000000
--- a/migrations/000002_alter_characters.up.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- ADD COLUMN exp uint16,
- ADD COLUMN weapon uint16,
- ADD COLUMN last_login integer;
-
-END;
\ No newline at end of file
diff --git a/migrations/000003_character_savedata.down.sql b/migrations/000003_character_savedata.down.sql
deleted file mode 100644
index d8d1ca8c6..000000000
--- a/migrations/000003_character_savedata.down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- DROP COLUMN savedata;
-
-END;
\ No newline at end of file
diff --git a/migrations/000003_character_savedata.up.sql b/migrations/000003_character_savedata.up.sql
deleted file mode 100644
index d0f39a223..000000000
--- a/migrations/000003_character_savedata.up.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- ADD COLUMN savedata bytea;
-
-END;
\ No newline at end of file
diff --git a/migrations/000004_character_additional.down.sql b/migrations/000004_character_additional.down.sql
deleted file mode 100644
index 5229381cb..000000000
--- a/migrations/000004_character_additional.down.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- DROP COLUMN decomyset,
- DROP COLUMN hunternavi,
- DROP COLUMN otomoairou,
- DROP COLUMN partner,
- DROP COLUMN platebox,
- DROP COLUMN platedata,
- DROP COLUMN platemyset,
- DROP COLUMN rengokudata;
-
-END;
\ No newline at end of file
diff --git a/migrations/000004_character_additional.up.sql b/migrations/000004_character_additional.up.sql
deleted file mode 100644
index 699351796..000000000
--- a/migrations/000004_character_additional.up.sql
+++ /dev/null
@@ -1,14 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- ADD COLUMN decomyset bytea,
- ADD COLUMN hunternavi bytea,
- ADD COLUMN otomoairou bytea,
- ADD COLUMN partner bytea,
- ADD COLUMN platebox bytea,
- ADD COLUMN platedata bytea,
- ADD COLUMN platemyset bytea,
- ADD COLUMN trophy bytea,
- ADD COLUMN rengokudata bytea;
-
-END;
diff --git a/migrations/000005_quests.down.sql b/migrations/000005_quests.down.sql
deleted file mode 100644
index 60eff8f22..000000000
--- a/migrations/000005_quests.down.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN;
-
-DROP TABLE IF EXISTS questlists;
-
-END;
\ No newline at end of file
diff --git a/migrations/000005_quests.up.sql b/migrations/000005_quests.up.sql
deleted file mode 100644
index 26a02f8d1..000000000
--- a/migrations/000005_quests.up.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-BEGIN;
-
-CREATE TABLE questlists (
- ind int NOT NULL PRIMARY KEY,
- questlist bytea
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000006_mercenary.down.sql b/migrations/000006_mercenary.down.sql
deleted file mode 100644
index 54cbd957b..000000000
--- a/migrations/000006_mercenary.down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- DROP COLUMN savemercenary;
-
-END;
\ No newline at end of file
diff --git a/migrations/000006_mercenary.up.sql b/migrations/000006_mercenary.up.sql
deleted file mode 100644
index af025dff0..000000000
--- a/migrations/000006_mercenary.up.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- ADD COLUMN savemercenary bytea;
-
-END;
\ No newline at end of file
diff --git a/migrations/000007_guilds.down.sql b/migrations/000007_guilds.down.sql
deleted file mode 100644
index 344ab854e..000000000
--- a/migrations/000007_guilds.down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-DROP TABLE guild_characters;
-DROP TABLE guilds;
-
-END;
\ No newline at end of file
diff --git a/migrations/000007_guilds.up.sql b/migrations/000007_guilds.up.sql
deleted file mode 100644
index e327c7db3..000000000
--- a/migrations/000007_guilds.up.sql
+++ /dev/null
@@ -1,22 +0,0 @@
-BEGIN;
-
-CREATE TABLE guilds
-(
- id serial NOT NULL PRIMARY KEY,
- name varchar(24),
- created_at timestamp DEFAULT NOW(),
- leader_id int NOT NULL,
- main_motto varchar(255) DEFAULT ''
-);
-
-CREATE TABLE guild_characters
-(
- id serial NOT NULL PRIMARY KEY,
- guild_id bigint REFERENCES guilds (id),
- character_id bigint REFERENCES characters (id),
- joined_at timestamp DEFAULT NOW()
-);
-
-CREATE UNIQUE INDEX guild_character_unique_index ON guild_characters (character_id);
-
-END;
\ No newline at end of file
diff --git a/migrations/000008_guild_additional.down.sql b/migrations/000008_guild_additional.down.sql
deleted file mode 100644
index 9252a98f2..000000000
--- a/migrations/000008_guild_additional.down.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-BEGIN;
-
-ALTER TABLE guilds
- DROP COLUMN rp;
-
-ALTER TABLE guild_characters
- DROP COLUMN is_applicant,
- DROP COLUMN is_sub_leader,
- DROP COLUMN order_index;
-
-END;
\ No newline at end of file
diff --git a/migrations/000008_guild_additional.up.sql b/migrations/000008_guild_additional.up.sql
deleted file mode 100644
index 7e16984d3..000000000
--- a/migrations/000008_guild_additional.up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-BEGIN;
-
-ALTER TABLE guild_characters
- ADD COLUMN is_applicant bool NOT NULL DEFAULT false,
- ADD COLUMN is_sub_leader bool NOT NULL DEFAULT false,
- ADD COLUMN order_index int NOT NULL DEFAULT 1;
-
-ALTER TABLE guilds
- ADD COLUMN rp uint16 NOT NULL DEFAULT 0;
-
-END;
diff --git a/migrations/000009_character_social.down.sql b/migrations/000009_character_social.down.sql
deleted file mode 100644
index 243ea6712..000000000
--- a/migrations/000009_character_social.down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- DROP COLUMN restrict_guild_scout;
-
-END;
\ No newline at end of file
diff --git a/migrations/000009_character_social.up.sql b/migrations/000009_character_social.up.sql
deleted file mode 100644
index f94ce2043..000000000
--- a/migrations/000009_character_social.up.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- ADD COLUMN restrict_guild_scout bool NOT NULL DEFAULT false;
-
-END;
\ No newline at end of file
diff --git a/migrations/000010_guild_comments_festival_hall.down.sql b/migrations/000010_guild_comments_festival_hall.down.sql
deleted file mode 100644
index c86d1ee5e..000000000
--- a/migrations/000010_guild_comments_festival_hall.down.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN;
-
-ALTER TABLE guilds
- DROP COLUMN comment,
- DROP COLUMN festival_colour,
- DROP COLUMN guild_hall;
-
-DROP TYPE festival_colour;
-
-END;
\ No newline at end of file
diff --git a/migrations/000010_guild_comments_festival_hall.up.sql b/migrations/000010_guild_comments_festival_hall.up.sql
deleted file mode 100644
index 3caec4149..000000000
--- a/migrations/000010_guild_comments_festival_hall.up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-BEGIN;
-
-CREATE TYPE festival_colour AS ENUM ('none', 'red', 'blue');
-
-ALTER TABLE guilds
- ADD COLUMN comment varchar(255) NOT NULL DEFAULT '',
- ADD COLUMN festival_colour festival_colour DEFAULT 'none',
- ADD COLUMN guild_hall int DEFAULT 0;
-
-
-END;
\ No newline at end of file
diff --git a/migrations/000011_character_points_minidata.down.sql b/migrations/000011_character_points_minidata.down.sql
deleted file mode 100644
index 557608be9..000000000
--- a/migrations/000011_character_points_minidata.down.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-BEGIN;
-
-ALTER TABLE characters
- DROP COLUMN minidata,
- DROP COLUMN gacha_trial,
- DROP COLUMN gacha_prem,
- DROP COLUMN gacha_items,
- DROP COLUMN daily_time,
- DROP COLUMN frontier_points,
- DROP COLUMN netcafe_points,
- DROP COLUMN house_info,
- DROP COLUMN login_boost,
- DROP COLUMN skin_hist,
- DROP COLUMN gcp;
-
-DROP TABLE fpoint_items;
-DROP TABLE gacha_shop;
-DROP TABLE gacha_shop_items;
-DROP TABLE lucky_box_state;
-DROP TABLE stepup_state;
-DROP TABLE normal_shop_items;
-DROP TABLE shop_item_state;
-
-END;
\ No newline at end of file
diff --git a/migrations/000011_character_points_minidata.up.sql b/migrations/000011_character_points_minidata.up.sql
deleted file mode 100644
index 29baa0790..000000000
--- a/migrations/000011_character_points_minidata.up.sql
+++ /dev/null
@@ -1,100 +0,0 @@
-BEGIN;
-ALTER TABLE characters
- ADD COLUMN minidata bytea,
- ADD COLUMN gacha_trial int,
- ADD COLUMN gacha_prem int,
- ADD COLUMN gacha_items bytea,
- ADD COLUMN daily_time timestamp,
- ADD COLUMN frontier_points int,
- ADD COLUMN netcafe_points int,
- ADD COLUMN house_info bytea,
- ADD COLUMN login_boost bytea,
- ADD COLUMN skin_hist bytea,
- ADD COLUMN kouryou_point int,
- ADD COLUMN gcp int;
-
-CREATE TABLE fpoint_items
-(
- hash int,
- itemType uint8,
- itemID uint16,
- quant uint16,
- itemValue uint16,
- tradeType uint8
-);
-
-
-CREATE TABLE gacha_shop
-(
- hash bigint,
- reqGR int,
- reqHR int,
- gachaName varchar(255),
- gachaLink0 varchar(255),
- gachaLink1 varchar(255),
- gachaLink2 varchar(255),
- extraIcon int,
- gachaType int,
- hideFlag bool
-);
-
-CREATE TABLE gacha_shop_items
-(
- shophash int,
- entryType uint8,
- itemhash int UNIQUE NOT NULL,
- currType uint8,
- currNumber uint16,
- currQuant uint16,
- percentage uint16,
- rarityIcon uint8,
- rollsCount uint8,
- itemCount uint8,
- dailyLimit uint8,
- itemType int[],
- itemId int[],
- quantity int[]
-);
-
-CREATE TABLE lucky_box_state
-(
- char_id bigint REFERENCES characters (id),
- shophash int UNIQUE NOT NULL,
- used_itemhash int[]
-);
-
-
-CREATE TABLE stepup_state
-(
- char_id bigint REFERENCES characters (id),
- shophash int UNIQUE NOT NULL,
- step_progression int,
- step_time timestamp
-);
-
-CREATE TABLE normal_shop_items
-(
- shoptype int,
- shopid int,
- itemhash int UNIQUE NOT NULL,
- itemID uint16,
- Points uint16,
- TradeQuantity uint16,
- rankReqLow uint16,
- rankReqHigh uint16,
- rankReqG uint16,
- storeLevelReq uint16,
- maximumQuantity uint16,
- boughtQuantity uint16,
- roadFloorsRequired uint16,
- weeklyFatalisKills uint16
-);
-
-CREATE TABLE shop_item_state
-(
- char_id bigint REFERENCES characters (id),
- itemhash int UNIQUE NOT NULL,
- usedquantity int
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000012_loginboost_etc.down.sql b/migrations/000012_loginboost_etc.down.sql
deleted file mode 100644
index 13102b0b0..000000000
--- a/migrations/000012_loginboost_etc.down.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN;
-
-DROP TABLE login_boost_state;
-
-END;
\ No newline at end of file
diff --git a/migrations/000012_loginboost_etc.up.sql b/migrations/000012_loginboost_etc.up.sql
deleted file mode 100644
index 4feff1790..000000000
--- a/migrations/000012_loginboost_etc.up.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN;
-
-CREATE TABLE login_boost_state
-(
- char_id bigint REFERENCES characters (id),
- week_req uint8,
- week_count uint8,
- available bool,
- end_time int,
- CONSTRAINT id_week UNIQUE(char_id, week_req)
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000013_shop_constraints.down.sql b/migrations/000013_shop_constraints.down.sql
deleted file mode 100644
index 7b5ac1242..000000000
--- a/migrations/000013_shop_constraints.down.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-BEGIN;
-
-ALTER TABLE shop_item_state DROP CONSTRAINT shop_item_state_id_itemhash;
-ALTER TABLE shop_item_state ADD CONSTRAINT shop_item_state_itemhash_key UNIQUE (itemhash);
-
-ALTER TABLE stepup_state DROP CONSTRAINT stepup_state_id_shophash;
-ALTER TABLE stepup_state ADD CONSTRAINT stepup_state_shophash_key UNIQUE (shophash);
-
-ALTER TABLE lucky_box_state DROP CONSTRAINT lucky_box_state_id_shophash;
-ALTER TABLE lucky_box_state ADD CONSTRAINT lucky_box_state_shophash_key UNIQUE (shophash);
-
-END;
\ No newline at end of file
diff --git a/migrations/000013_shop_constraints.up.sql b/migrations/000013_shop_constraints.up.sql
deleted file mode 100644
index a48e81ac2..000000000
--- a/migrations/000013_shop_constraints.up.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-BEGIN;
-
-ALTER TABLE shop_item_state DROP CONSTRAINT shop_item_state_itemhash_key;
-ALTER TABLE shop_item_state ADD CONSTRAINT shop_item_state_id_itemhash UNIQUE(char_id, itemhash);
-
-ALTER TABLE stepup_state DROP CONSTRAINT stepup_state_shophash_key;
-ALTER TABLE stepup_state ADD CONSTRAINT stepup_state_id_shophash UNIQUE(char_id, shophash);
-
-ALTER TABLE lucky_box_state DROP CONSTRAINT lucky_box_state_shophash_key;
-ALTER TABLE lucky_box_state ADD CONSTRAINT lucky_box_state_id_shophash UNIQUE(char_id, shophash);
-
-END;
\ No newline at end of file
diff --git a/migrations/000014_guild_flags_applications.down.sql b/migrations/000014_guild_flags_applications.down.sql
deleted file mode 100644
index 6cfe86288..000000000
--- a/migrations/000014_guild_flags_applications.down.sql
+++ /dev/null
@@ -1,18 +0,0 @@
-BEGIN;
-ALTER TABLE guild_characters
- RENAME COLUMN avoid_leadership TO is_sub_leader;
-
-ALTER TABLE guild_characters
- ADD COLUMN is_applicant bool NOT NULL DEFAULT false;
-
-ALTER TABLE guilds
- DROP COLUMN icon,
- ALTER COLUMN main_motto TYPE varchar USING '',
- DROP COLUMN sub_motto;
-
-ALTER TABLE guilds
- ALTER COLUMN main_motto SET DEFAULT '';
-
-DROP TABLE guild_applications;
-DROP TYPE guild_application_type;
-END;
\ No newline at end of file
diff --git a/migrations/000014_guild_flags_applications.up.sql b/migrations/000014_guild_flags_applications.up.sql
deleted file mode 100644
index 4bc09668a..000000000
--- a/migrations/000014_guild_flags_applications.up.sql
+++ /dev/null
@@ -1,30 +0,0 @@
-BEGIN;
-CREATE TYPE guild_application_type AS ENUM ('applied', 'invited');
-
-CREATE TABLE guild_applications
-(
- id serial NOT NULL PRIMARY KEY,
- guild_id int NOT NULL REFERENCES guilds (id),
- character_id int NOT NULL REFERENCES characters (id),
- actor_id int NOT NULL REFERENCES characters (id),
- application_type guild_application_type NOT NULL,
- created_at timestamp NOT NULL DEFAULT now(),
- CONSTRAINT guild_application_character_id UNIQUE (guild_id, character_id)
-);
-
-CREATE INDEX guild_application_type_index ON guild_applications (application_type);
-
-ALTER TABLE guild_characters
- DROP COLUMN is_applicant;
-
-ALTER TABLE guild_characters
- RENAME COLUMN is_sub_leader TO avoid_leadership;
-
-ALTER TABLE guilds
- ALTER COLUMN main_motto SET DEFAULT 0;
-
-ALTER TABLE guilds
- ADD COLUMN icon bytea,
- ADD COLUMN sub_motto int DEFAULT 0,
- ALTER COLUMN main_motto TYPE int USING 0;
-END;
\ No newline at end of file
diff --git a/migrations/000015_mail.down.sql b/migrations/000015_mail.down.sql
deleted file mode 100644
index 8ed5b834f..000000000
--- a/migrations/000015_mail.down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN;
-DROP TABLE mail;
-END;
\ No newline at end of file
diff --git a/migrations/000015_mail.up.sql b/migrations/000015_mail.up.sql
deleted file mode 100644
index ba0dc4edd..000000000
--- a/migrations/000015_mail.up.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-BEGIN;
-CREATE TABLE mail
-(
- id SERIAL NOT NULL PRIMARY KEY,
- sender_id INT NOT NULL REFERENCES characters (id),
- recipient_id INT NOT NULL REFERENCES characters (id),
- subject VARCHAR NOT NULL DEFAULT '',
- body VARCHAR NOT NULL DEFAULT '',
- read BOOL NOT NULL DEFAULT FALSE,
- attached_item_received BOOL NOT NULL DEFAULT FALSE,
- attached_item INT DEFAULT NULL,
- attached_item_amount INT NOT NULL DEFAULT 1,
- is_guild_invite BOOL NOT NULL DEFAULT FALSE,
- created_at TIMESTAMP NOT NULL DEFAULT NOW(),
- deleted BOOL NOT NULL DEFAULT FALSE
-);
-
-CREATE INDEX mail_recipient_deleted_created_id_index ON mail (recipient_id, deleted, created_at DESC, id DESC);
-END;
\ No newline at end of file
diff --git a/migrations/000016_server.down.sql b/migrations/000016_server.down.sql
deleted file mode 100644
index a5fb2d6b0..000000000
--- a/migrations/000016_server.down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN;
-DROP TABLE public.servers;
-END;
\ No newline at end of file
diff --git a/migrations/000016_server.up.sql b/migrations/000016_server.up.sql
deleted file mode 100644
index f6a7798e7..000000000
--- a/migrations/000016_server.up.sql
+++ /dev/null
@@ -1,21 +0,0 @@
-BEGIN;
--- Table: public.servers
-
--- DROP TABLE IF EXISTS public.servers;
-
-CREATE TABLE IF NOT EXISTS public.servers
-(
- server_id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
- server_name text COLLATE pg_catalog."default",
- season integer,
- current_players integer,
- event_id integer,
- event_expiration integer,
- CONSTRAINT servers_pkey PRIMARY KEY (server_id)
-)
-
-TABLESPACE pg_default;
-
-ALTER TABLE IF EXISTS public.servers
- OWNER to postgres;
-END;
\ No newline at end of file
diff --git a/migrations/000017_account.down.sql b/migrations/000017_account.down.sql
deleted file mode 100644
index c52957af0..000000000
--- a/migrations/000017_account.down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN;
-DROP TABLE public.account_ban;
-DROP TABLE public.account_history;
-DROP TABLE public.account_moderation;
-DROP TABLE public.account_sub;
-END;
\ No newline at end of file
diff --git a/migrations/000017_account.up.sql b/migrations/000017_account.up.sql
deleted file mode 100644
index f636d619f..000000000
--- a/migrations/000017_account.up.sql
+++ /dev/null
@@ -1,45 +0,0 @@
-BEGIN;
-
-CREATE TABLE IF NOT EXISTS public.account_ban
-(
- user_id integer NOT NULL,
- title text COLLATE pg_catalog."default",
- reason text COLLATE pg_catalog."default",
- date text COLLATE pg_catalog."default",
- pass_origin text COLLATE pg_catalog."default",
- pass_block text COLLATE pg_catalog."default",
- CONSTRAINT ban_pkey PRIMARY KEY (user_id)
-);
-
-CREATE TABLE IF NOT EXISTS public.account_history
-(
- report_id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
- user_id integer,
- title text COLLATE pg_catalog."default",
- reason text COLLATE pg_catalog."default",
- date date,
- CONSTRAINT account_history_pkey PRIMARY KEY (report_id)
-);
-
-CREATE TABLE IF NOT EXISTS public.account_moderation
-(
- id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
- username text COLLATE pg_catalog."default",
- password text COLLATE pg_catalog."default",
- type text COLLATE pg_catalog."default",
- CONSTRAINT account_moderation_pkey PRIMARY KEY (id)
-);
-
-CREATE TABLE IF NOT EXISTS public.account_sub
-(
- id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
- discord_id text COLLATE pg_catalog."default",
- erupe_account text COLLATE pg_catalog."default",
- erupe_password text COLLATE pg_catalog."default",
- date_inscription date,
- country text COLLATE pg_catalog."default",
- presentation text COLLATE pg_catalog."default",
- CONSTRAINT account_auth_pkey PRIMARY KEY (id)
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000018_event_week.down.sql b/migrations/000018_event_week.down.sql
deleted file mode 100644
index 756df1f22..000000000
--- a/migrations/000018_event_week.down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN;
-DROP TABLE public.event_week;
-END;
\ No newline at end of file
diff --git a/migrations/000018_event_week.up.sql b/migrations/000018_event_week.up.sql
deleted file mode 100644
index f536871f2..000000000
--- a/migrations/000018_event_week.up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-BEGIN;
-
-CREATE TABLE IF NOT EXISTS public.event_week
-(
- id integer NOT NULL,
- event_id integer NOT NULL,
- date_expiration integer NOT NULL,
- CONSTRAINT event_week_pkey PRIMARY KEY (id)
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000019_gook.down.sql b/migrations/000019_gook.down.sql
deleted file mode 100644
index a4b544e9a..000000000
--- a/migrations/000019_gook.down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN;
-DROP TABLE public.gook;
-END;
\ No newline at end of file
diff --git a/migrations/000019_gook.up.sql b/migrations/000019_gook.up.sql
deleted file mode 100644
index fe5c051c0..000000000
--- a/migrations/000019_gook.up.sql
+++ /dev/null
@@ -1,20 +0,0 @@
-BEGIN;
-
-CREATE TABLE IF NOT EXISTS public.gook
-(
- id serial NOT NULL PRIMARY KEY,
- gook0 bytea,
- gook1 bytea,
- gook2 bytea,
- gook3 bytea,
- gook4 bytea,
- gook5 bytea,
- gook0status boolean,
- gook1status boolean,
- gook2status boolean,
- gook3status boolean,
- gook4status boolean,
- gook5status boolean
-);
-
-END;
\ No newline at end of file
diff --git a/migrations/000020_history.down.sql b/migrations/000020_history.down.sql
deleted file mode 100644
index 623bd53c8..000000000
--- a/migrations/000020_history.down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-BEGIN;
-DROP TABLE public.history;
-END;
\ No newline at end of file
diff --git a/migrations/000020_history.up.sql b/migrations/000020_history.up.sql
deleted file mode 100644
index 96d6b36c8..000000000
--- a/migrations/000020_history.up.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN;
-
-CREATE TABLE IF NOT EXISTS public.history
-(
- user_id integer,
- admin_id integer,
- report_id integer NOT NULL,
- title text COLLATE pg_catalog."default",
- reason text COLLATE pg_catalog."default",
- CONSTRAINT history_pkey PRIMARY KEY (report_id)
-);
-
-END;
\ No newline at end of file
diff --git a/network/clientctx/clientcontext.go b/network/clientctx/clientcontext.go
index 0f890f6d7..021ae3299 100644
--- a/network/clientctx/clientcontext.go
+++ b/network/clientctx/clientcontext.go
@@ -1,8 +1,4 @@
package clientctx
-import "erupe-ce/common/stringsupport"
-
// ClientContext holds contextual data required for packet encoding/decoding.
-type ClientContext struct {
- StrConv *stringsupport.StringConverter
-}
+type ClientContext struct{} // Unused
diff --git a/network/mhfpacket/msg_mhf_enumerate_guild.go b/network/mhfpacket/msg_mhf_enumerate_guild.go
index 65edbc555..691f8241f 100644
--- a/network/mhfpacket/msg_mhf_enumerate_guild.go
+++ b/network/mhfpacket/msg_mhf_enumerate_guild.go
@@ -32,6 +32,7 @@ type MsgMhfEnumerateGuild struct {
AckHandle uint32
Type EnumerateGuildType
Page uint8
+ Sorting bool
RawDataPayload []byte
}
@@ -45,6 +46,8 @@ func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
m.AckHandle = bf.ReadUint32()
m.Type = EnumerateGuildType(bf.ReadUint8())
m.Page = bf.ReadUint8()
+ m.Sorting = bf.ReadBool()
+ _ = bf.ReadUint8()
m.RawDataPayload = bf.DataFromCurrent()
bf.Seek(-2, io.SeekEnd)
return nil
diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go
index b343dd0c4..0702a5b3e 100644
--- a/network/mhfpacket/msg_sys_update_right.go
+++ b/network/mhfpacket/msg_sys_update_right.go
@@ -2,6 +2,8 @@ package mhfpacket
import (
"errors"
+ ps "erupe-ce/common/pascalstring"
+ "golang.org/x/exp/slices"
"erupe-ce/common/byteframe"
"erupe-ce/network"
@@ -34,6 +36,12 @@ type ClientRight struct {
Timestamp uint32
}
+type Course struct {
+ Aliases []string
+ ID uint16
+ Value uint32
+}
+
// MsgSysUpdateRight represents the MSG_SYS_UPDATE_RIGHT
type MsgSysUpdateRight struct {
ClientRespAckHandle uint32 // If non-0, requests the client to send back a MSG_SYS_ACK packet with this value.
@@ -63,9 +71,40 @@ func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame, ctx *clientctx.Client
bf.WriteUint16(v.Unk0)
bf.WriteUint32(v.Timestamp)
}
-
- bf.WriteUint16(m.UnkSize) // String of upto 0x800 bytes, update client login token / password in the game's launcherstate struct.
- //bf.WriteBytes(m.UpdatedClientLoginToken)
-
+ ps.Uint16(bf, "", false) // update client login token / password in the game's launcherstate struct
return nil
}
+
+func Courses() []Course {
+ var courses = []Course{
+ {[]string{"Trial", "TL"}, 1, 0x00000002},
+ {[]string{"HunterLife", "HL"}, 2, 0x00000004},
+ {[]string{"ExtraA", "Extra", "EX"}, 3, 0x00000008},
+ {[]string{"ExtraB"}, 4, 0x00000010},
+ {[]string{"Mobile"}, 5, 0x00000020},
+ {[]string{"Premium"}, 6, 0x00000040},
+ {[]string{"Pallone"}, 7, 0x00000080},
+ {[]string{"Assist", "Legend", "Rasta"}, 8, 0x00000100}, // Legend
+ {[]string{"Netcafe", "N", "Cafe"}, 9, 0x00000200},
+ {[]string{"Hiden", "Secret"}, 10, 0x00000400}, // Secret
+ {[]string{"HunterSupport", "HunterAid", "Support", "Royal", "Aid"}, 11, 0x00000800}, // Royal
+ {[]string{"NetcafeBoost", "NBoost", "Boost"}, 12, 0x00001000},
+ }
+ return courses
+}
+
+// GetCourseStruct returns a slice of Course(s) from a rights integer
+func GetCourseStruct(rights uint32) []Course {
+ var resp []Course
+ s := Courses()
+ slices.SortStableFunc(s, func(i, j Course) bool {
+ return i.ID > j.ID
+ })
+ for _, course := range s {
+ if rights-course.Value < 0x80000000 {
+ resp = append(resp, course)
+ rights -= course.Value
+ }
+ }
+ return resp
+}
diff --git a/patch-schema/active-feature.sql b/patch-schema/active-feature.sql
new file mode 100644
index 000000000..f8b835100
--- /dev/null
+++ b/patch-schema/active-feature.sql
@@ -0,0 +1,9 @@
+BEGIN;
+
+CREATE TABLE IF NOT EXISTS public.feature_weapon
+(
+ start_time timestamp without time zone NOT NULL,
+ featured integer NOT NULL
+);
+
+END;
\ No newline at end of file
diff --git a/patch-schema/netcafe-2.sql b/patch-schema/netcafe-2.sql
new file mode 100644
index 000000000..d2a1f0763
--- /dev/null
+++ b/patch-schema/netcafe-2.sql
@@ -0,0 +1,6 @@
+BEGIN;
+
+ALTER TABLE IF EXISTS public.characters
+ ADD COLUMN cafe_reset timestamp without time zone;
+
+END;
\ No newline at end of file
diff --git a/patch-schema/netcafe.sql b/patch-schema/netcafe.sql
index e284742ce..563e10fb0 100644
--- a/patch-schema/netcafe.sql
+++ b/patch-schema/netcafe.sql
@@ -27,14 +27,4 @@ CREATE TABLE IF NOT EXISTS public.cafe_accepted
character_id integer NOT NULL
);
-INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity)
-VALUES
- (1800, 17, 0, 250),
- (3600, 17, 0, 500),
- (7200, 17, 0, 1000),
- (10800, 17, 0, 1500),
- (18000, 17, 0, 1750),
- (28800, 17, 0, 3000),
- (43200, 17, 0, 4000);
-
END;
\ No newline at end of file
diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go
index 1eb014145..5d19d93f4 100644
--- a/server/channelserver/handlers.go
+++ b/server/channelserver/handlers.go
@@ -6,7 +6,6 @@ import (
"erupe-ce/common/stringsupport"
"fmt"
"io"
- "math"
"net"
"strings"
"time"
@@ -74,26 +73,16 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
}
func updateRights(s *Session) {
- s.rights = uint32(0x0E)
- s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&s.rights)
-
- rights := make([]mhfpacket.ClientRight, 0)
- tempRights := s.rights
- for i := 30; i > 0; i-- {
- right := uint32(math.Pow(2, float64(i)))
- if tempRights-right < 0x80000000 {
- if i == 1 {
- continue
- }
- rights = append(rights, mhfpacket.ClientRight{ID: uint16(i), Timestamp: 0x70DB59F0})
- tempRights -= right
- }
+ rightsInt := uint32(0x0E)
+ s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt)
+ s.courses = mhfpacket.GetCourseStruct(rightsInt)
+ rights := []mhfpacket.ClientRight{{1, 0, 0}}
+ for _, course := range s.courses {
+ rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0})
}
- rights = append(rights, mhfpacket.ClientRight{ID: 1, Timestamp: 0})
-
update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0,
- Bitfield: s.rights,
+ Bitfield: rightsInt,
Rights: rights,
UnkSize: 0,
}
@@ -190,6 +179,16 @@ func logoutPlayer(s *Session) {
s.server.Unlock()
for _, stage := range s.server.stages {
+ // Tell sessions registered to disconnecting players quest to unregister
+ if stage.host != nil && stage.host.charID == s.charID {
+ for _, sess := range s.server.sessions {
+ for rSlot := range stage.reservedClientSlots {
+ if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" {
+ sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
+ }
+ }
+ }
+ }
for session := range stage.clients {
if session.charID == s.charID {
delete(stage.clients, session)
@@ -214,7 +213,7 @@ func logoutPlayer(s *Session) {
timePlayed += sessionTime
var rpGained int
- if s.rights >= 0x40000000 { // N Course
+ if s.FindCourse("Netcafe").ID != 0 {
rpGained = timePlayed / 900
timePlayed = timePlayed % 900
} else {
diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go
index c7d826429..15b01f510 100644
--- a/server/channelserver/handlers_cafe.go
+++ b/server/channelserver/handlers_cafe.go
@@ -4,6 +4,7 @@ import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
+ "fmt"
"go.uber.org/zap"
"io"
"time"
@@ -71,15 +72,22 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetCafeDuration)
bf := byteframe.NewByteFrame()
+ var cafeReset time.Time
+ err := s.server.db.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.charID).Scan(&cafeReset)
+ if Time_Current_Adjusted().After(cafeReset) {
+ cafeReset = TimeWeekNext()
+ s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2; DELETE FROM cafe_accepted WHERE character_id=$2`, cafeReset, s.charID)
+ }
+
var cafeTime uint32
- err := s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime)
+ err = s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime)
if err != nil {
panic(err)
}
cafeTime = uint32(Time_Current_Adjusted().Unix()) - uint32(s.sessionStart) + cafeTime
bf.WriteUint32(cafeTime) // Total cafe time
bf.WriteUint16(0)
- ps.Uint16(bf, "Resets at next maintenance", true)
+ ps.Uint16(bf, fmt.Sprintf("Resets on %s %d", cafeReset.Month().String(), cafeReset.Day()), true)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go
index 3791ea241..64666d9af 100644
--- a/server/channelserver/handlers_cast_binary.go
+++ b/server/channelserver/handlers_cast_binary.go
@@ -7,6 +7,7 @@ import (
"erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket"
"fmt"
+ "golang.org/x/exp/slices"
"math"
"math/rand"
"strings"
@@ -19,6 +20,7 @@ import (
const (
BinaryMessageTypeState = 0
BinaryMessageTypeChat = 1
+ BinaryMessageTypeQuest = 2
BinaryMessageTypeData = 3
BinaryMessageTypeMailNotify = 4
BinaryMessageTypeEmote = 6
@@ -89,6 +91,18 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
}
}
+ if s.server.erupeConfig.DevModeOptions.QuestDebugTools == true && s.server.erupeConfig.DevMode {
+ if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x02 && len(pkt.RawDataPayload) > 32 {
+ // This is only correct most of the time
+ tmp.ReadBytes(20)
+ tmp.SetLE()
+ x := tmp.ReadFloat32()
+ y := tmp.ReadFloat32()
+ z := tmp.ReadFloat32()
+ s.logger.Debug("Coord", zap.Float32s("XYZ", []float32{x, y, z}))
+ }
+ }
+
// Parse out the real casted binary payload
var msgBinTargeted *binpacket.MsgBinTargeted
var authorLen, msgLen uint16
@@ -298,6 +312,53 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
}
}
+ if strings.HasPrefix(chatMessage.Message, commands["Course"].Prefix) {
+ if commands["Course"].Enabled {
+ var name string
+ n, err := fmt.Sscanf(chatMessage.Message, "!course %s", &name)
+ if err != nil || n != 1 {
+ sendServerChatMessage(s, "Error in command. Format: !course ")
+ } else {
+ name = strings.ToLower(name)
+ for _, course := range mhfpacket.Courses() {
+ for _, alias := range course.Aliases {
+ if strings.ToLower(name) == strings.ToLower(alias) {
+ if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) {
+ if s.FindCourse(name).Value != 0 {
+ ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool {
+ for _, alias := range c.Aliases {
+ if strings.ToLower(name) == strings.ToLower(alias) {
+ return true
+ }
+ }
+ return false
+ })
+ if ei != -1 {
+ s.courses = append(s.courses[:ei], s.courses[ei+1:]...)
+ sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled.`, course.Aliases[0]))
+ }
+ } else {
+ s.courses = append(s.courses, course)
+ sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled.`, course.Aliases[0]))
+ }
+ var newInt uint32
+ for _, course := range s.courses {
+ newInt += course.Value
+ }
+ s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID)
+ updateRights(s)
+ } else {
+ sendServerChatMessage(s, fmt.Sprintf(`%s Course is locked.`, course.Aliases[0]))
+ }
+ }
+ }
+ }
+ }
+ } else {
+ sendDisabledCommandMessage(s, commands["Course"])
+ }
+ }
+
if strings.HasPrefix(chatMessage.Message, commands["Raviente"].Prefix) {
if commands["Raviente"].Enabled {
if getRaviSemaphore(s) != "" {
diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go
index b641d3973..28521d10d 100644
--- a/server/channelserver/handlers_data.go
+++ b/server/channelserver/handlers_data.go
@@ -2,6 +2,7 @@ package channelserver
import (
"encoding/hex"
+ "erupe-ce/common/bfutil"
"erupe-ce/common/stringsupport"
"fmt"
"io"
@@ -9,7 +10,6 @@ import (
"os"
"path/filepath"
- "erupe-ce/common/bfutil"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
"erupe-ce/server/channelserver/compression/deltacomp"
@@ -49,7 +49,7 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
characterSaveData.Save(s)
s.logger.Info("Wrote recompressed savedata back to DB.")
- characterSaveData.Name = s.clientContext.StrConv.MustDecode(bfutil.UpToNull(characterSaveData.decompSave[88:100]))
+ characterSaveData.Name = stringsupport.SJISToUTF8(bfutil.UpToNull(characterSaveData.decompSave[88:100]))
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character name in db", zap.Error(err))
diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go
index b6765f998..95227709f 100644
--- a/server/channelserver/handlers_event.go
+++ b/server/channelserver/handlers_event.go
@@ -53,38 +53,46 @@ func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) {
}
type activeFeature struct {
- StartTime time.Time
- ActiveFeatures uint32
- Unk1 uint16
+ StartTime time.Time `db:"start_time"`
+ ActiveFeatures uint32 `db:"featured"`
}
func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
- persistentEventSchedule := make([]activeFeature, 8) // generate day after weekly restart
- for x := -1; x < 7; x++ {
- feat := generateActiveWeapons(14) // number of active weapons
- // TODO: only generate this once per restart (server should be restarted weekly)
- // then load data from db instead of regenerating
- persistentEventSchedule[x+1] = activeFeature{
- StartTime: Time_Current_Midnight().Add(time.Duration(24*x) * time.Hour),
- ActiveFeatures: uint32(feat),
- Unk1: 0,
+
+ var features []activeFeature
+ rows, _ := s.server.db.Queryx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1 OR start_time=$2`, Time_Current_Midnight().Add(-24*time.Hour), Time_Current_Midnight())
+ for rows.Next() {
+ var feature activeFeature
+ rows.StructScan(&feature)
+ features = append(features, feature)
+ }
+
+ if len(features) < 2 {
+ if len(features) == 0 {
+ feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
+ feature.StartTime = Time_Current_Midnight().Add(-24 * time.Hour)
+ features = append(features, feature)
+ s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
}
+ feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons)
+ feature.StartTime = Time_Current_Midnight()
+ features = append(features, feature)
+ s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures)
}
- resp := byteframe.NewByteFrame()
- resp.WriteUint8(uint8(len(persistentEventSchedule))) // Entry count, client only parses the first 7 or 8.
- resp.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix())) // 5 minutes ago server time
-
- for _, es := range persistentEventSchedule {
- resp.WriteUint32(uint32(es.StartTime.Unix()))
- resp.WriteUint32(es.ActiveFeatures)
- resp.WriteUint16(es.Unk1)
+ bf := byteframe.NewByteFrame()
+ bf.WriteUint8(2)
+ bf.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
+ for _, feature := range features {
+ bf.WriteUint32(uint32(feature.StartTime.Unix()))
+ bf.WriteUint32(feature.ActiveFeatures)
+ bf.WriteUint16(0)
}
- doAckBufSucceed(s, pkt.AckHandle, resp.Data())
+ doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
-func generateActiveWeapons(count int) int {
+func generateFeatureWeapons(count int) activeFeature {
nums := make([]int, 0)
var result int
r := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -104,7 +112,7 @@ func generateActiveWeapons(count int) int {
for _, num := range nums {
result += int(math.Pow(2, float64(num)))
}
- return result
+ return activeFeature{ActiveFeatures: uint32(result)}
}
type loginBoost struct {
diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go
index 6e5080ac3..9f925f3dc 100644
--- a/server/channelserver/handlers_festa.go
+++ b/server/channelserver/handlers_festa.go
@@ -6,6 +6,7 @@ import (
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
"math/rand"
+ "sort"
"time"
)
@@ -253,11 +254,19 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
- var souls uint32
+ var souls, exists uint32
s.server.db.QueryRow("SELECT souls FROM guild_characters WHERE character_id=$1", s.charID).Scan(&souls)
+ err = s.server.db.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.charID).Scan(&exists)
bf := byteframe.NewByteFrame()
bf.WriteUint32(souls)
- bf.WriteUint32(0) // unk
+ if err != nil {
+ bf.WriteBool(true)
+ bf.WriteBool(false)
+ } else {
+ bf.WriteBool(false)
+ bf.WriteBool(true)
+ }
+ bf.WriteUint16(0) // Unk
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
@@ -280,10 +289,10 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {
return
}
resp.WriteUint32(guild.Souls)
- resp.WriteUint32(0) // unk
- resp.WriteUint32(0) // unk, rank?
- resp.WriteUint32(0) // unk
- resp.WriteUint32(0) // unk
+ resp.WriteUint32(1) // unk
+ resp.WriteUint32(1) // unk
+ resp.WriteUint32(1) // unk, rank?
+ resp.WriteUint32(1) // unk
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
@@ -302,6 +311,9 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(len(members)))
bf.WriteUint16(0) // Unk
+ sort.Slice(members, func(i, j int) bool {
+ return members[i].Souls > members[j].Souls
+ })
for _, member := range members {
bf.WriteUint32(member.CharID)
bf.WriteUint32(member.Souls)
@@ -342,6 +354,7 @@ func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireFesta)
+ s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
@@ -368,7 +381,7 @@ type Prize struct {
func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaPersonalPrize)
- rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='personal'")
+ rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='personal'`, s.charID)
var count uint32
prizeData := byteframe.NewByteFrame()
for rows.Next() {
@@ -394,7 +407,7 @@ func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket)
func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateFestaIntermediatePrize)
- rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='guild'")
+ rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='guild'`, s.charID)
var count uint32
prizeData := byteframe.NewByteFrame()
for rows.Next() {
diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go
index 3a4b047fc..a6129bd1e 100644
--- a/server/channelserver/handlers_guild.go
+++ b/server/channelserver/handlers_guild.go
@@ -1034,7 +1034,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
}
applicants, err := GetGuildMembers(s, guild.ID, true)
- if err != nil {
+ if err != nil || (characterGuildData != nil && !characterGuildData.CanRecruit()) {
bf.WriteUint16(0)
} else {
bf.WriteUint16(uint16(len(applicants)))
@@ -1101,9 +1101,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
switch pkt.Type {
case mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME:
- bf.ReadBytes(10)
+ bf.ReadBytes(8)
searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()))
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2 LIMIT 11`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1111,9 +1111,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_NAME:
- bf.ReadBytes(10)
+ bf.ReadBytes(8)
searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()))
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2 LIMIT 11`, guildInfoSelectQuery), searchTerm, pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1121,7 +1121,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_ID:
- bf.ReadBytes(2)
ID := bf.ReadUint32()
rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE leader_id = $1`, guildInfoSelectQuery), ID)
if err == nil {
@@ -1131,11 +1130,10 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_MEMBERS:
- sorting := bf.ReadUint8()
- if sorting == 1 {
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ if pkt.Sorting {
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
} else {
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
}
if err == nil {
for rows.Next() {
@@ -1144,11 +1142,10 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION:
- sorting := bf.ReadUint8()
- if sorting == 1 {
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ if pkt.Sorting {
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
} else {
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
}
if err == nil {
for rows.Next() {
@@ -1157,11 +1154,10 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_RANK:
- sorting := bf.ReadUint8()
- if sorting == 1 {
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ if pkt.Sorting {
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
} else {
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
}
if err == nil {
for rows.Next() {
@@ -1170,10 +1166,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_GUILD_TYPE_MOTTO:
- bf.ReadBytes(2)
mainMotto := bf.ReadUint16()
subMotto := bf.ReadUint16()
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3 LIMIT 11`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1182,7 +1177,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
case mhfpacket.ENUMERATE_GUILD_TYPE_RECRUITING:
// Assume the player wants the newest guilds with open recruitment
- rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE recruiting=true ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10)
+ rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE recruiting=true ORDER BY id DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10)
if err == nil {
for rows.Next() {
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
@@ -1202,7 +1197,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
switch pkt.Type {
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME:
- bf.ReadBytes(10)
+ bf.ReadBytes(8)
searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
for _, alliance := range tempAlliances {
if strings.Contains(alliance.Name, searchTerm) {
@@ -1210,7 +1205,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME:
- bf.ReadBytes(10)
+ bf.ReadBytes(8)
searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
for _, alliance := range tempAlliances {
if strings.Contains(alliance.ParentGuild.LeaderName, searchTerm) {
@@ -1218,7 +1213,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID:
- bf.ReadBytes(2)
ID := bf.ReadUint32()
for _, alliance := range tempAlliances {
if alliance.ParentGuild.LeaderCharID == ID {
@@ -1226,8 +1220,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
}
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS:
- sorting := bf.ReadBool()
- if sorting {
+ if pkt.Sorting {
sort.Slice(tempAlliances, func(i, j int) bool {
return tempAlliances[i].TotalMembers > tempAlliances[j].TotalMembers
})
@@ -1238,8 +1231,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
}
alliances = tempAlliances
case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION:
- sorting := bf.ReadBool()
- if sorting {
+ if pkt.Sorting {
sort.Slice(tempAlliances, func(i, j int) bool {
return tempAlliances[i].CreatedAt.Unix() > tempAlliances[j].CreatedAt.Unix()
})
@@ -1260,16 +1252,14 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
bf = byteframe.NewByteFrame()
if pkt.Type > 8 {
- if len(guilds) > 10 {
- bf.WriteUint16(10)
- } else {
- bf.WriteUint16(uint16(len(alliances)))
+ hasNextPage := false
+ if len(alliances) > 10 {
+ hasNextPage = true
+ alliances = alliances[:10]
}
- bf.WriteUint8(0x00) // Unk
- for i, alliance := range alliances {
- if i == 10 {
- break
- }
+ bf.WriteUint16(uint16(len(alliances)))
+ bf.WriteBool(hasNextPage)
+ for _, alliance := range alliances {
bf.WriteUint32(alliance.ID)
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
bf.WriteUint16(alliance.TotalMembers)
@@ -1288,16 +1278,14 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
bf.WriteBool(true) // TODO: Enable GuildAlliance applications
}
} else {
+ hasNextPage := false
if len(guilds) > 10 {
- bf.WriteUint16(10)
- } else {
- bf.WriteUint16(uint16(len(guilds)))
+ hasNextPage = true
+ guilds = guilds[:10]
}
- bf.WriteUint8(0x01) // Unk
- for i, guild := range guilds {
- if i == 10 {
- break
- }
+ bf.WriteUint16(uint16(len(guilds)))
+ bf.WriteBool(hasNextPage)
+ for _, guild := range guilds {
bf.WriteUint32(guild.ID)
bf.WriteUint32(guild.LeaderCharID)
bf.WriteUint16(guild.MemberCount)
diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go
index c01b0e006..10c60d04f 100644
--- a/server/channelserver/handlers_quest.go
+++ b/server/channelserver/handlers_quest.go
@@ -2,7 +2,7 @@ package channelserver
import (
"fmt"
- "io"
+ "go.uber.org/zap"
"io/ioutil"
"os"
"path/filepath"
@@ -14,14 +14,24 @@ import (
func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysGetFile)
- // Debug print the request.
if pkt.IsScenario {
- fmt.Printf("%+v\n", pkt.ScenarioIdentifer)
+ if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode {
+ s.logger.Debug(
+ "Scenario",
+ zap.Uint8("CategoryID", pkt.ScenarioIdentifer.CategoryID),
+ zap.Uint32("MainID", pkt.ScenarioIdentifer.MainID),
+ zap.Uint8("ChapterID", pkt.ScenarioIdentifer.ChapterID),
+ zap.Uint8("Flags", pkt.ScenarioIdentifer.Flags),
+ )
+ }
filename := fmt.Sprintf("%d_0_0_0_S%d_T%d_C%d", pkt.ScenarioIdentifer.CategoryID, pkt.ScenarioIdentifer.MainID, pkt.ScenarioIdentifer.Flags, pkt.ScenarioIdentifer.ChapterID)
// Read the scenario file.
data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename)))
if err != nil {
- panic(err)
+ s.logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", s.server.erupeConfig.BinPath, filename))
+ // This will crash the game.
+ doAckBufSucceed(s, pkt.AckHandle, data)
+ return
}
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
@@ -32,10 +42,19 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
}
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
+ if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode {
+ s.logger.Debug(
+ "Quest",
+ zap.String("Filename", pkt.Filename),
+ )
+ }
// Get quest file.
data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename)))
if err != nil {
- s.logger.Fatal(fmt.Sprintf("Failed to open quest file: quests/%s.bin", pkt.Filename))
+ s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename))
+ // This will crash the game.
+ doAckBufSucceed(s, pkt.AckHandle, data)
+ return
}
doAckBufSucceed(s, pkt.AckHandle, data)
}
diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go
index d9f58df57..c1e8d2dbd 100644
--- a/server/channelserver/handlers_rengoku.go
+++ b/server/channelserver/handlers_rengoku.go
@@ -3,6 +3,7 @@ package channelserver
import (
ps "erupe-ce/common/pascalstring"
"fmt"
+ "github.com/jmoiron/sqlx"
"io/ioutil"
"path/filepath"
@@ -96,20 +97,13 @@ func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, data)
}
-const rengokuScoreQuery = `
-SELECT max_stages_mp, max_points_mp, max_stages_sp, max_points_sp, c.name, gc.guild_id
-FROM rengoku_score rs
+const rengokuScoreQuery = `, c.name FROM rengoku_score rs
LEFT JOIN characters c ON c.id = rs.character_id
-LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id
-`
+LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id `
type RengokuScore struct {
- Name string `db:"name"`
- GuildID int `db:"guild_id"`
- MaxStagesMP uint32 `db:"max_stages_mp"`
- MaxPointsMP uint32 `db:"max_points_mp"`
- MaxStagesSP uint32 `db:"max_stages_sp"`
- MaxPointsSP uint32 `db:"max_points_sp"`
+ Name string `db:"name"`
+ Score uint32 `db:"score"`
}
func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
@@ -121,170 +115,64 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
guild = nil
}
+ if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 {
+ if guild == nil {
+ doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11))
+ return
+ }
+ }
+
var score RengokuScore
+ var selfExist bool
i := uint32(1)
bf := byteframe.NewByteFrame()
scoreData := byteframe.NewByteFrame()
+
+ var rows *sqlx.Rows
switch pkt.Leaderboard {
- case 0: // Max stage overall MP
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_mp DESC", rengokuScoreQuery))
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxStagesMP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxStagesMP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- case 1: // Max RdP overall MP
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_mp DESC", rengokuScoreQuery))
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxPointsMP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxPointsMP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- case 2: // Max stage guild MP
- if guild != nil {
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID)
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxStagesMP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxStagesMP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- } else {
- bf.WriteBytes(make([]byte, 11))
- }
- case 3: // Max RdP guild MP
- if guild != nil {
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID)
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxPointsMP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxPointsMP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- } else {
- bf.WriteBytes(make([]byte, 11))
- }
- case 4: // Max stage overall SP
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_sp DESC", rengokuScoreQuery))
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxStagesSP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxStagesSP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- case 5: // Max RdP overall SP
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_sp DESC", rengokuScoreQuery))
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxPointsSP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxPointsSP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- case 6: // Max stage guild SP
- if guild != nil {
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID)
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxStagesSP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxStagesSP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- } else {
- bf.WriteBytes(make([]byte, 11))
- }
- case 7: // Max RdP guild SP
- if guild != nil {
- rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID)
- for rows.Next() {
- rows.StructScan(&score)
- if score.Name == s.Name {
- bf.WriteUint32(i)
- bf.WriteUint32(score.MaxPointsSP)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- }
- scoreData.WriteUint32(i)
- scoreData.WriteUint32(score.MaxPointsSP)
- ps.Uint8(scoreData, score.Name, true)
- ps.Uint8(scoreData, "", false)
- i++
- }
- } else {
- bf.WriteBytes(make([]byte, 11))
- }
+ case 0:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s ORDER BY max_stages_mp DESC", rengokuScoreQuery))
+ case 1:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s ORDER BY max_points_mp DESC", rengokuScoreQuery))
+ case 2:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID)
+ case 3:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID)
+ case 4:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s ORDER BY max_stages_sp DESC", rengokuScoreQuery))
+ case 5:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s ORDER BY max_points_sp DESC", rengokuScoreQuery))
+ case 6:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID)
+ case 7:
+ rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID)
}
- if i == 1 {
- bf.WriteUint32(1)
- bf.WriteUint32(0)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- bf.WriteUint8(1)
- bf.WriteUint32(1)
- bf.WriteUint32(0)
- ps.Uint8(bf, s.Name, true)
- ps.Uint8(bf, "", false)
- } else {
- bf.WriteUint8(uint8(i) - 1)
- bf.WriteBytes(scoreData.Data())
+
+ for rows.Next() {
+ rows.StructScan(&score)
+ if score.Name == s.Name {
+ bf.WriteUint32(i)
+ bf.WriteUint32(score.Score)
+ ps.Uint8(bf, s.Name, true)
+ ps.Uint8(bf, "", false)
+ selfExist = true
+ }
+ if i > 100 {
+ i++
+ continue
+ }
+ scoreData.WriteUint32(i)
+ scoreData.WriteUint32(score.Score)
+ ps.Uint8(scoreData, score.Name, true)
+ ps.Uint8(scoreData, "", false)
+ i++
}
+
+ if !selfExist {
+ bf.WriteBytes(make([]byte, 10))
+ }
+ bf.WriteUint8(uint8(i) - 1)
+ bf.WriteBytes(scoreData.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go
index 906480be7..90ecdec99 100644
--- a/server/channelserver/handlers_stage.go
+++ b/server/channelserver/handlers_stage.go
@@ -19,6 +19,7 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} else {
stage := NewStage(pkt.StageID)
+ stage.host = s
stage.maxPlayers = uint16(pkt.PlayerCount)
s.server.stages[stage.id] = stage
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
@@ -42,6 +43,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
stage = s.server.stages[stageID]
s.server.Unlock()
stage.Lock()
+ stage.host = s
stage.clients[s] = s.charID
stage.Unlock()
}
diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go
index 90430f4da..39a96f40f 100644
--- a/server/channelserver/sys_session.go
+++ b/server/channelserver/sys_session.go
@@ -6,17 +6,16 @@ import (
"fmt"
"io"
"net"
+ "strings"
"sync"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/common/stringstack"
- "erupe-ce/common/stringsupport"
"erupe-ce/network"
"erupe-ce/network/clientctx"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
- "golang.org/x/text/encoding/japanese"
)
type packet struct {
@@ -43,7 +42,7 @@ type Session struct {
charID uint32
logKey []byte
sessionStart int64
- rights uint32
+ courses []mhfpacket.Course
token string
kqf []byte
kqfOverride bool
@@ -68,16 +67,12 @@ type Session struct {
// NewSession creates a new Session type.
func NewSession(server *Server, conn net.Conn) *Session {
s := &Session{
- logger: server.logger.Named(conn.RemoteAddr().String()),
- server: server,
- rawConn: conn,
- cryptConn: network.NewCryptConn(conn),
- sendPackets: make(chan packet, 20),
- clientContext: &clientctx.ClientContext{
- StrConv: &stringsupport.StringConverter{
- Encoding: japanese.ShiftJIS,
- },
- },
+ logger: server.logger.Named(conn.RemoteAddr().String()),
+ server: server,
+ rawConn: conn,
+ cryptConn: network.NewCryptConn(conn),
+ sendPackets: make(chan packet, 20),
+ clientContext: &clientctx.ClientContext{}, // Unused
sessionStart: Time_Current_Adjusted().Unix(),
stageMoveStack: stringstack.New(),
}
@@ -268,3 +263,14 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data))
}
}
+
+func (s *Session) FindCourse(name string) mhfpacket.Course {
+ for _, course := range s.courses {
+ for _, alias := range course.Aliases {
+ if strings.ToLower(name) == strings.ToLower(alias) {
+ return course
+ }
+ }
+ }
+ return mhfpacket.Course{}
+}
diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go
index 827b2d6be..4cd96a7f8 100644
--- a/server/channelserver/sys_stage.go
+++ b/server/channelserver/sys_stage.go
@@ -46,6 +46,7 @@ type Stage struct {
// other clients expect the server to echo them back in the exact same format.
rawBinaryData map[stageBinaryKey][]byte
+ host *Session
maxPlayers uint16
password string
createdAt string
diff --git a/server/entranceserver/entrance_server.go b/server/entranceserver/entrance_server.go
index 56f300c27..706aac8b3 100644
--- a/server/entranceserver/entrance_server.go
+++ b/server/entranceserver/entrance_server.go
@@ -90,6 +90,7 @@ func (s *Server) acceptClients() {
}
func (s *Server) handleEntranceServerConnection(conn net.Conn) {
+ defer conn.Close()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
n, err := io.ReadFull(conn, nullInit)
@@ -118,5 +119,4 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) {
cc.SendPacket(data)
// Close because we only need to send the response once.
// Any further requests from the client will come from a new connection.
- conn.Close()
}
diff --git a/server/signserver/dbutils.go b/server/signserver/dbutils.go
index 5e99d4c85..213a74a14 100644
--- a/server/signserver/dbutils.go
+++ b/server/signserver/dbutils.go
@@ -148,7 +148,7 @@ func (s *Server) getFriendsForCharacters(chars []character) []members {
if err != nil {
continue
}
- for i, _ := range charFriends {
+ for i := range charFriends {
charFriends[i].CID = char.ID
}
friends = append(friends, charFriends...)
diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go
index cbad6405c..3966af8d6 100644
--- a/server/signserver/dsgn_resp.go
+++ b/server/signserver/dsgn_resp.go
@@ -42,13 +42,23 @@ func (s *Session) makeSignInResp(uid int) []byte {
bf := byteframe.NewByteFrame()
- bf.WriteUint8(1) // resp_code
- bf.WriteUint8(0) // file/patch server count
+ bf.WriteUint8(1) // resp_code
+ if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" {
+ bf.WriteUint8(2)
+ } else {
+ bf.WriteUint8(0)
+ }
bf.WriteUint8(1) // entrance server count
bf.WriteUint8(uint8(len(chars))) // character count
bf.WriteUint32(0xFFFFFFFF) // login_token_number
bf.WriteBytes([]byte(token)) // login_token
bf.WriteUint32(uint32(time.Now().Unix())) // current time
+ if s.server.erupeConfig.DevMode {
+ if s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" {
+ ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerManifest, false)
+ ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerFile, false)
+ }
+ }
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false)
lastPlayed := uint32(0)
diff --git a/server/signserver/session.go b/server/signserver/session.go
index aef6508b1..6b2e38b8c 100644
--- a/server/signserver/session.go
+++ b/server/signserver/session.go
@@ -16,32 +16,19 @@ import (
type Session struct {
sync.Mutex
logger *zap.Logger
- sid int
server *Server
- rawConn *net.Conn
+ rawConn net.Conn
cryptConn *network.CryptConn
}
-func (s *Session) fail() {
- s.server.Lock()
- delete(s.server.sessions, s.sid)
- s.server.Unlock()
-
-}
-
func (s *Session) work() {
- for {
- pkt, err := s.cryptConn.ReadPacket()
- if err != nil {
- s.fail()
- return
- }
-
- err = s.handlePacket(pkt)
- if err != nil {
- s.fail()
- return
- }
+ pkt, err := s.cryptConn.ReadPacket()
+ if err != nil {
+ return
+ }
+ err = s.handlePacket(pkt)
+ if err != nil {
+ return
}
}
@@ -61,6 +48,7 @@ func (s *Session) handlePacket(pkt []byte) error {
case "DELETE:100":
loginTokenString := string(bf.ReadNullTerminatedBytes())
characterID := int(bf.ReadUint32())
+ _ = int(bf.ReadUint32()) // login_token_number
s.server.deleteCharacter(characterID, loginTokenString)
sugar.Infof("Deleted character ID: %v\n", characterID)
err := s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS
@@ -78,13 +66,13 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
reqUsername := string(bf.ReadNullTerminatedBytes())
reqPassword := string(bf.ReadNullTerminatedBytes())
- reqUnk := string(bf.ReadNullTerminatedBytes())
+ reqSkey := string(bf.ReadNullTerminatedBytes())
s.server.logger.Info(
"Got sign in request",
zap.String("reqUsername", reqUsername),
zap.String("reqPassword", reqPassword),
- zap.String("reqUnk", reqUnk),
+ zap.String("reqSkey", reqSkey),
)
newCharaReq := false
@@ -105,12 +93,15 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
s.logger.Info("Account not found", zap.String("reqUsername", reqUsername))
serverRespBytes = makeSignInFailureResp(SIGN_EAUTH)
- // HACK(Andoryuuta): Create a new account if it doesn't exit.
- s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword))
- err = s.server.registerDBAccount(reqUsername, reqPassword)
- if err != nil {
- s.logger.Info("Error on creating new account", zap.Error(err))
- serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
+ if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.AutoCreateAccount {
+ s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword))
+ err = s.server.registerDBAccount(reqUsername, reqPassword)
+ if err != nil {
+ s.logger.Info("Error on creating new account", zap.Error(err))
+ serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
+ break
+ }
+ } else {
break
}
diff --git a/server/signserver/sign_server.go b/server/signserver/sign_server.go
index 02bafb10d..6d567e126 100644
--- a/server/signserver/sign_server.go
+++ b/server/signserver/sign_server.go
@@ -24,7 +24,6 @@ type Server struct {
sync.Mutex
logger *zap.Logger
erupeConfig *config.Config
- sid int
sessions map[int]*Session
db *sqlx.DB
listener net.Listener
@@ -36,8 +35,6 @@ func NewServer(config *Config) *Server {
s := &Server{
logger: config.Logger,
erupeConfig: config.ErupeConfig,
- sid: 0,
- sessions: make(map[int]*Session),
db: config.DB,
}
return s
@@ -84,20 +81,19 @@ func (s *Server) acceptClients() {
}
}
- go s.handleConnection(s.sid, conn)
- s.sid++
+ go s.handleConnection(conn)
}
}
-func (s *Server) handleConnection(sid int, conn net.Conn) {
+func (s *Server) handleConnection(conn net.Conn) {
s.logger.Info("Got connection to sign server", zap.String("remoteaddr", conn.RemoteAddr().String()))
+ defer conn.Close()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
_, err := io.ReadFull(conn, nullInit)
if err != nil {
- fmt.Println(err)
- conn.Close()
+ s.logger.Error("Error initialising sign server connection", zap.Error(err))
return
}
@@ -105,15 +101,10 @@ func (s *Server) handleConnection(sid int, conn net.Conn) {
session := &Session{
logger: s.logger,
server: s,
- rawConn: &conn,
+ rawConn: conn,
cryptConn: network.NewCryptConn(conn),
}
- // Add the session to the server's sessions map.
- s.Lock()
- s.sessions[sid] = session
- s.Unlock()
-
// Do the session's work.
session.work()
}