mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-02-06 01:57:38 +01:00
Merge branch 'main' into feature/diva
# Conflicts: # server/channelserver/handlers_quest.go
This commit is contained in:
13
bundled-schema/NetcafeDefaults.sql
Normal file
13
bundled-schema/NetcafeDefaults.sql
Normal file
@@ -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;
|
||||
145
config.json
145
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": "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.1 Beta!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you.",
|
||||
"cleandb": false,
|
||||
"maxlauncherhr": false,
|
||||
"HideLoginNotice": false,
|
||||
"LoginNotice": "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.1 Beta!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you.",
|
||||
"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 }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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,7 +31,9 @@ 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
|
||||
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.
|
||||
@@ -44,6 +48,7 @@ type DevModeOptions struct {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
33
go.mod
33
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
|
||||
)
|
||||
|
||||
26
go.sum
26
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=
|
||||
|
||||
6
main.go
6
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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,8 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
DROP COLUMN exp,
|
||||
DROP COLUMN weapon,
|
||||
DROP COLUMN last_login;
|
||||
|
||||
END;
|
||||
@@ -1,8 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
ADD COLUMN exp uint16,
|
||||
ADD COLUMN weapon uint16,
|
||||
ADD COLUMN last_login integer;
|
||||
|
||||
END;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
DROP COLUMN savedata;
|
||||
|
||||
END;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
ADD COLUMN savedata bytea;
|
||||
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,5 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
DROP TABLE IF EXISTS questlists;
|
||||
|
||||
END;
|
||||
@@ -1,8 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE questlists (
|
||||
ind int NOT NULL PRIMARY KEY,
|
||||
questlist bytea
|
||||
);
|
||||
|
||||
END;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
DROP COLUMN savemercenary;
|
||||
|
||||
END;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
ADD COLUMN savemercenary bytea;
|
||||
|
||||
END;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
DROP TABLE guild_characters;
|
||||
DROP TABLE guilds;
|
||||
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
DROP COLUMN restrict_guild_scout;
|
||||
|
||||
END;
|
||||
@@ -1,6 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE characters
|
||||
ADD COLUMN restrict_guild_scout bool NOT NULL DEFAULT false;
|
||||
|
||||
END;
|
||||
@@ -1,10 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE guilds
|
||||
DROP COLUMN comment,
|
||||
DROP COLUMN festival_colour,
|
||||
DROP COLUMN guild_hall;
|
||||
|
||||
DROP TYPE festival_colour;
|
||||
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,5 +0,0 @@
|
||||
BEGIN;
|
||||
|
||||
DROP TABLE login_boost_state;
|
||||
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,3 +0,0 @@
|
||||
BEGIN;
|
||||
DROP TABLE mail;
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -1,3 +0,0 @@
|
||||
BEGIN;
|
||||
DROP TABLE public.servers;
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,3 +0,0 @@
|
||||
BEGIN;
|
||||
DROP TABLE public.event_week;
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -1,3 +0,0 @@
|
||||
BEGIN;
|
||||
DROP TABLE public.gook;
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -1,3 +0,0 @@
|
||||
BEGIN;
|
||||
DROP TABLE public.history;
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
9
patch-schema/active-feature.sql
Normal file
9
patch-schema/active-feature.sql
Normal file
@@ -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;
|
||||
6
patch-schema/netcafe-2.sql
Normal file
6
patch-schema/netcafe-2.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE IF EXISTS public.characters
|
||||
ADD COLUMN cafe_reset timestamp without time zone;
|
||||
|
||||
END;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
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: uint16(i), Timestamp: 0x70DB59F0})
|
||||
tempRights -= right
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <name>")
|
||||
} 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) != "" {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
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)
|
||||
}
|
||||
|
||||
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, 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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 {
|
||||
hasNextPage := false
|
||||
if len(alliances) > 10 {
|
||||
hasNextPage = true
|
||||
alliances = alliances[:10]
|
||||
}
|
||||
bf.WriteUint16(uint16(len(alliances)))
|
||||
}
|
||||
bf.WriteUint8(0x00) // Unk
|
||||
for i, alliance := range alliances {
|
||||
if i == 10 {
|
||||
break
|
||||
}
|
||||
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 {
|
||||
hasNextPage = true
|
||||
guilds = guilds[:10]
|
||||
}
|
||||
bf.WriteUint16(uint16(len(guilds)))
|
||||
}
|
||||
bf.WriteUint8(0x01) // Unk
|
||||
for i, guild := range guilds {
|
||||
if i == 10 {
|
||||
break
|
||||
}
|
||||
bf.WriteBool(hasNextPage)
|
||||
for _, guild := range guilds {
|
||||
bf.WriteUint32(guild.ID)
|
||||
bf.WriteUint32(guild.LeaderCharID)
|
||||
bf.WriteUint16(guild.MemberCount)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
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))
|
||||
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)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
rows.StructScan(&score)
|
||||
if score.Name == s.Name {
|
||||
bf.WriteUint32(i)
|
||||
bf.WriteUint32(score.MaxStagesMP)
|
||||
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.MaxStagesMP)
|
||||
scoreData.WriteUint32(score.Score)
|
||||
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)
|
||||
|
||||
if !selfExist {
|
||||
bf.WriteBytes(make([]byte, 10))
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
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())
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -73,11 +72,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
|
||||
rawConn: conn,
|
||||
cryptConn: network.NewCryptConn(conn),
|
||||
sendPackets: make(chan packet, 20),
|
||||
clientContext: &clientctx.ClientContext{
|
||||
StrConv: &stringsupport.StringConverter{
|
||||
Encoding: japanese.ShiftJIS,
|
||||
},
|
||||
},
|
||||
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{}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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...)
|
||||
|
||||
@@ -43,12 +43,22 @@ func (s *Session) makeSignInResp(uid int) []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
bf.WriteUint8(1) // resp_code
|
||||
bf.WriteUint8(0) // file/patch server count
|
||||
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)
|
||||
|
||||
@@ -16,33 +16,20 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) handlePacket(pkt []byte) error {
|
||||
@@ -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,7 +93,7 @@ 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.
|
||||
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 {
|
||||
@@ -113,6 +101,9 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
var id int
|
||||
err = s.server.db.QueryRow("SELECT id FROM users WHERE username = $1", reqUsername).Scan(&id)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user