mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-12 23:14:36 +01:00
rewrite command processor and i18n
This commit is contained in:
80
config.json
80
config.json
@@ -114,64 +114,52 @@
|
||||
"RelayChannelID": ""
|
||||
}
|
||||
},
|
||||
"Commands": [
|
||||
{
|
||||
"Name": "Help",
|
||||
"Commands": {
|
||||
"help": {
|
||||
"Enabled": true,
|
||||
"Description": "Show enabled chat commands",
|
||||
"Prefix": "help"
|
||||
}, {
|
||||
"Name": "Rights",
|
||||
"Description": "Show enabled chat commands"
|
||||
},
|
||||
"rights":{
|
||||
"Enabled": false,
|
||||
"Description": "Overwrite the Rights value on your account",
|
||||
"Prefix": "rights"
|
||||
}, {
|
||||
"Name": "Raviente",
|
||||
"Description": "Overwrite the Rights value on your account"
|
||||
},
|
||||
"ravi": {
|
||||
"Enabled": true,
|
||||
"Description": "Various Raviente siege commands",
|
||||
"Prefix": "ravi"
|
||||
}, {
|
||||
"Name": "Teleport",
|
||||
"Description": "Various Raviente siege commands"
|
||||
},
|
||||
"teleport": {
|
||||
"Enabled": false,
|
||||
"Description": "Teleport to specified coordinates",
|
||||
"Prefix": "tele"
|
||||
}, {
|
||||
"Name": "Reload",
|
||||
"Description": "Teleport to specified coordinates"
|
||||
},
|
||||
"reload": {
|
||||
"Enabled": true,
|
||||
"Description": "Reload all players in your Land",
|
||||
"Prefix": "reload"
|
||||
}, {
|
||||
"Name": "KeyQuest",
|
||||
"Description": "Reload all players in your Land"
|
||||
},
|
||||
"kqf":{
|
||||
"Enabled": false,
|
||||
"Description": "Overwrite your HR Key Quest progress",
|
||||
"Prefix": "kqf"
|
||||
}, {
|
||||
"Name": "Course",
|
||||
"Description": "Get or Set your HR Key Quest progress"
|
||||
},
|
||||
"course": {
|
||||
"Enabled": true,
|
||||
"Description": "Toggle Courses on your account",
|
||||
"Prefix": "course"
|
||||
}, {
|
||||
"Name": "PSN",
|
||||
"Description": "Toggle Courses on your account"
|
||||
},
|
||||
"psn": {
|
||||
"Enabled": true,
|
||||
"Description": "Link a PlayStation Network ID to your account",
|
||||
"Prefix": "psn"
|
||||
}, {
|
||||
"Name": "Discord",
|
||||
"Description": "Link a PlayStation Network ID to your account"
|
||||
},
|
||||
"discord": {
|
||||
"Enabled": true,
|
||||
"Description": "Generate a token to link your Discord account",
|
||||
"Prefix": "discord"
|
||||
}, {
|
||||
"Name": "Ban",
|
||||
"Description": "Generate a token to link your Discord account"
|
||||
},
|
||||
"ban": {
|
||||
"Enabled": false,
|
||||
"Description": "Ban/Temp Ban a user",
|
||||
"Prefix": "ban"
|
||||
}, {
|
||||
"Name": "Timer",
|
||||
"Description": "Ban/Temp Ban a user"
|
||||
},
|
||||
"timer": {
|
||||
"Enabled": true,
|
||||
"Description": "Toggle the Quest timer",
|
||||
"Prefix": "timer"
|
||||
"Description": "Toggle the Quest timer"
|
||||
}
|
||||
],
|
||||
},
|
||||
"Courses": [
|
||||
{"Name": "HunterLife", "Enabled": true},
|
||||
{"Name": "Extra", "Enabled": true},
|
||||
|
||||
@@ -93,7 +93,7 @@ type Config struct {
|
||||
DebugOptions DebugOptions
|
||||
GameplayOptions GameplayOptions
|
||||
Discord Discord
|
||||
Commands []Command
|
||||
Commands map[string]Command
|
||||
Courses []Course
|
||||
Database Database
|
||||
Sign Sign
|
||||
|
||||
425
server/channelserver/chat_commands.go
Normal file
425
server/channelserver/chat_commands.go
Normal file
@@ -0,0 +1,425 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"erupe-ce/utils/byteframe"
|
||||
"erupe-ce/utils/db"
|
||||
"erupe-ce/utils/mhfcid"
|
||||
"erupe-ce/utils/mhfcourse"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type commandFunc func(s *Session, args []string) error
|
||||
|
||||
var commandMap = map[string]commandFunc{
|
||||
"ban": ban,
|
||||
"timer": timer,
|
||||
"psn": psn,
|
||||
"reload": reload,
|
||||
"kqf": kqf,
|
||||
"rights": rights,
|
||||
"course": course,
|
||||
"ravi": ravi,
|
||||
"teleport": teleport,
|
||||
"discord": discord,
|
||||
"help": help,
|
||||
}
|
||||
|
||||
func executeCommand(s *Session, input string) error {
|
||||
args := strings.Split(input[len(config.GetConfig().CommandPrefix):], " ")
|
||||
if command, exists := commandMap[args[0]]; exists {
|
||||
if !s.isOp() {
|
||||
if commandConfig, exists := config.GetConfig().Commands[args[0]]; exists {
|
||||
if !commandConfig.Enabled {
|
||||
s.sendMessage(t("commands.disabled", v{"command": args[0]}))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return command(s, args[1:])
|
||||
} else {
|
||||
return fmt.Errorf("unknown command: %s", args[0])
|
||||
}
|
||||
}
|
||||
|
||||
func ban(s *Session, args []string) error {
|
||||
if !s.isOp() {
|
||||
s.sendMessage(t("commands.no_op", v{}))
|
||||
return nil
|
||||
}
|
||||
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) < 1 {
|
||||
s.sendMessage(t("commands.ban.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
cid := mhfcid.ConvertCID(args[0])
|
||||
if cid == 0 {
|
||||
s.sendMessage(t("commands.ban.error.invalid", v{}))
|
||||
return nil
|
||||
}
|
||||
|
||||
var expiry time.Time
|
||||
if len(args) > 1 {
|
||||
duration, err := parseDuration(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
expiry = time.Now().Add(duration)
|
||||
}
|
||||
|
||||
var uid uint32
|
||||
var uname string
|
||||
err = database.QueryRow(`SELECT id, username FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, cid).Scan(&uid, &uname)
|
||||
if err == nil {
|
||||
if expiry.IsZero() {
|
||||
database.Exec(`INSERT INTO bans VALUES ($1)
|
||||
ON CONFLICT (user_id) DO UPDATE SET expires=NULL`, uid)
|
||||
s.sendMessage(t("commands.ban.success.permanent", v{"username": uname}))
|
||||
} else {
|
||||
database.Exec(`INSERT INTO bans VALUES ($1, $2)
|
||||
ON CONFLICT (user_id) DO UPDATE SET expires=$2`, uid, expiry)
|
||||
s.sendMessage(t("commands.ban.success.temporary", v{"username": uname, "expiry": expiry.Format(time.DateTime)}))
|
||||
}
|
||||
s.Server.DisconnectUser(uid)
|
||||
} else {
|
||||
s.sendMessage(t("commands.ban.error.invalid", v{}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func timer(s *Session, _ []string) error {
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var state bool
|
||||
database.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&state)
|
||||
database.Exec(`UPDATE users u SET timer=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, !state, s.CharID)
|
||||
if state {
|
||||
s.sendMessage(t("commands.timer.disabled", v{}))
|
||||
} else {
|
||||
s.sendMessage(t("commands.timer.enabled", v{}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func psn(s *Session, args []string) error {
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) < 1 {
|
||||
s.sendMessage(t("commands.psn.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
var exists int
|
||||
database.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, args[1]).Scan(&exists)
|
||||
if exists == 0 {
|
||||
_, err = database.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, args[1], s.CharID)
|
||||
if err == nil {
|
||||
s.sendMessage(t("commands.psn.success", v{"psn": args[1]}))
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
s.sendMessage(t("commands.psn.error.exists", v{"psn": args[1]}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func reload(s *Session, _ []string) error {
|
||||
s.sendMessage(t("commands.reload", v{}))
|
||||
var temp mhfpacket.MHFPacket
|
||||
for _, object := range s.stage.objects {
|
||||
if object.ownerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
for _, session := range s.Server.sessions {
|
||||
if s == session {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.CharID}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
for _, session := range s.Server.sessions {
|
||||
if s == session {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysInsertUser{CharID: session.CharID}
|
||||
s.QueueSendMHF(temp)
|
||||
for i := 0; i < 3; i++ {
|
||||
temp = &mhfpacket.MsgSysNotifyUserBinary{
|
||||
CharID: session.CharID,
|
||||
BinaryType: uint8(i + 1),
|
||||
}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
}
|
||||
for _, obj := range s.stage.objects {
|
||||
if obj.ownerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: obj.id,
|
||||
X: obj.x,
|
||||
Y: obj.y,
|
||||
Z: obj.z,
|
||||
Unk0: 0,
|
||||
OwnerCharID: obj.ownerCharID,
|
||||
}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func kqf(s *Session, args []string) error {
|
||||
if len(args) < 1 {
|
||||
s.sendMessage(t("commands.kqf.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
if args[0] == "get" {
|
||||
s.sendMessage(t("commands.kqf.get", v{"kqf": fmt.Sprintf("%x", s.kqf)}))
|
||||
return nil
|
||||
} else if args[0] == "set" {
|
||||
if len(args) < 2 || len(args[1]) != 16 {
|
||||
s.sendMessage(t("commands.kqf.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
hexd, _ := hex.DecodeString(args[1])
|
||||
s.kqf = hexd
|
||||
s.kqfOverride = true
|
||||
s.sendMessage(t("commands.kqf.set", v{}))
|
||||
return nil
|
||||
} else {
|
||||
s.sendMessage(t("commands.kqf.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func rights(s *Session, args []string) error {
|
||||
if len(args) < 1 {
|
||||
s.sendMessage(t("commands.rights.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, _ := strconv.Atoi(args[0])
|
||||
_, err = database.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", r, s.CharID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.sendMessage(t("commands.rights.success", v{"rights": args[0]}))
|
||||
return nil
|
||||
}
|
||||
|
||||
func course(s *Session, args []string) error {
|
||||
if len(args) < 1 {
|
||||
s.sendMessage(t("commands.course.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, course := range mhfcourse.Courses() {
|
||||
for _, alias := range course.Aliases() {
|
||||
if strings.ToLower(args[1]) == strings.ToLower(alias) {
|
||||
if slices.Contains(config.GetConfig().Courses, config.Course{Name: course.Aliases()[0], Enabled: true}) {
|
||||
var delta, rightsInt uint32
|
||||
if mhfcourse.CourseExists(course.ID, s.courses) {
|
||||
ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool {
|
||||
for _, alias := range c.Aliases() {
|
||||
if strings.ToLower(args[1]) == strings.ToLower(alias) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
if ei != -1 {
|
||||
delta = uint32(-1 * math.Pow(2, float64(course.ID)))
|
||||
s.sendMessage(t("commands.course.disabled", v{"course": course.Aliases()[0]}))
|
||||
}
|
||||
} else {
|
||||
delta = uint32(math.Pow(2, float64(course.ID)))
|
||||
s.sendMessage(t("commands.course.enabled", v{"course": course.Aliases()[0]}))
|
||||
}
|
||||
err = database.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.CharID).Scan(&rightsInt)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
_, err = database.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.CharID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
updateRights(s)
|
||||
} else {
|
||||
s.sendMessage(t("commands.course.locked", v{"course": course.Aliases()[0]}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ravi(s *Session, args []string) error {
|
||||
if len(args) < 1 {
|
||||
s.sendMessage(t("commands.ravi.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.Server.getRaviSemaphore() == nil {
|
||||
s.sendMessage(t("commands.ravi.error.no_players", v{}))
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "start":
|
||||
if s.Server.raviente.register[1] == 0 {
|
||||
s.Server.raviente.register[1] = s.Server.raviente.register[3]
|
||||
s.sendMessage(t("commands.ravi.start", v{}))
|
||||
s.notifyRavi()
|
||||
} else {
|
||||
s.sendMessage(t("commands.ravi.error.start", v{}))
|
||||
}
|
||||
case "multiplier":
|
||||
s.sendMessage(t("commands.ravi.multiplier", v{"multiplier": fmt.Sprintf("%.2f", s.Server.GetRaviMultiplier())}))
|
||||
case "sr", "sendres", "resurrection", "resurrect", "res":
|
||||
if config.GetConfig().ClientID != config.ZZ {
|
||||
s.sendMessage(t("commands.ravi.version", v{}))
|
||||
return nil
|
||||
}
|
||||
if s.Server.raviente.state[28] > 0 {
|
||||
s.sendMessage(t("commands.ravi.resurrect.send", v{}))
|
||||
s.Server.raviente.state[28] = 0
|
||||
} else {
|
||||
s.sendMessage(t("commands.ravi.resurrect.error", v{}))
|
||||
}
|
||||
case "ss", "sendsed":
|
||||
if config.GetConfig().ClientID != config.ZZ {
|
||||
s.sendMessage(t("commands.ravi.version", v{}))
|
||||
return nil
|
||||
}
|
||||
HP := s.Server.raviente.state[0] + s.Server.raviente.state[1] + s.Server.raviente.state[2] + s.Server.raviente.state[3] + s.Server.raviente.state[4]
|
||||
s.Server.raviente.support[1] = HP
|
||||
case "rs", "reqsed":
|
||||
if config.GetConfig().ClientID != config.ZZ {
|
||||
s.sendMessage(t("commands.ravi.version", v{}))
|
||||
return nil
|
||||
}
|
||||
HP := s.Server.raviente.state[0] + s.Server.raviente.state[1] + s.Server.raviente.state[2] + s.Server.raviente.state[3] + s.Server.raviente.state[4]
|
||||
s.Server.raviente.support[1] = HP + 1
|
||||
default:
|
||||
s.sendMessage(t("commands.ravi.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func teleport(s *Session, args []string) error {
|
||||
if len(args) < 2 {
|
||||
s.sendMessage(t("commands.teleport.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
||||
return nil
|
||||
}
|
||||
|
||||
x, _ := strconv.ParseInt(args[0], 10, 16)
|
||||
y, _ := strconv.ParseInt(args[1], 10, 16)
|
||||
payload := byteframe.NewByteFrame()
|
||||
payload.SetLE()
|
||||
payload.WriteUint8(2) // SetState type(position == 2)
|
||||
payload.WriteInt16(int16(x))
|
||||
payload.WriteInt16(int16(y))
|
||||
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
|
||||
CharID: s.CharID,
|
||||
MessageType: BinaryMessageTypeState,
|
||||
RawDataPayload: payload.Data(),
|
||||
})
|
||||
s.sendMessage(t("commands.teleport.success", v{"x": fmt.Sprintf("%d", x), "y": fmt.Sprintf("%d", y)}))
|
||||
return nil
|
||||
}
|
||||
|
||||
func discord(s *Session, _ []string) error {
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var _token string
|
||||
err = database.QueryRow(`SELECT discord_token FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&_token)
|
||||
if err != nil {
|
||||
randToken := make([]byte, 4)
|
||||
_, err = rand.Read(randToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_token = fmt.Sprintf("%x-%x", randToken[:2], randToken[2:])
|
||||
_, err = database.Exec(`UPDATE users u SET discord_token = $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, _token, s.CharID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
s.sendMessage(t("commands.discord.success", v{"token": _token}))
|
||||
return nil
|
||||
}
|
||||
|
||||
func help(s *Session, _ []string) error {
|
||||
for command, _config := range config.GetConfig().Commands {
|
||||
if _config.Enabled || s.isOp() {
|
||||
s.sendMessage(fmt.Sprintf("%s%s: %s", config.GetConfig().CommandPrefix, command, _config.Description))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseDuration(input string) (time.Duration, error) {
|
||||
unit := input[len(input)-1:]
|
||||
value := input[:len(input)-1]
|
||||
|
||||
num, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid duration value: %s", value)
|
||||
}
|
||||
|
||||
switch unit {
|
||||
case "s":
|
||||
return time.Duration(num) * time.Second, nil
|
||||
case "m":
|
||||
return time.Duration(num) * time.Minute, nil
|
||||
case "h":
|
||||
return time.Duration(num) * time.Hour, nil
|
||||
case "d":
|
||||
return time.Duration(num) * 24 * time.Hour, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid duration unit: %s", unit)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,18 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/network/binpacket"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"erupe-ce/utils/byteframe"
|
||||
"erupe-ce/utils/db"
|
||||
"erupe-ce/utils/logger"
|
||||
"erupe-ce/utils/mhfcid"
|
||||
"erupe-ce/utils/mhfcourse"
|
||||
"erupe-ce/utils/token"
|
||||
"sync"
|
||||
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -55,21 +47,16 @@ func (server *ChannelServer) initCommands() {
|
||||
|
||||
commandLogger := logger.Get().Named("command")
|
||||
cmds := config.GetConfig().Commands
|
||||
for _, cmd := range cmds {
|
||||
commands[cmd.Name] = cmd
|
||||
if cmd.Enabled {
|
||||
commandLogger.Info(fmt.Sprintf("%s: Enabled, prefix: %s", cmd.Name, cmd.Prefix))
|
||||
for cmd, conf := range cmds {
|
||||
if conf.Enabled {
|
||||
commandLogger.Info(fmt.Sprintf("%s: Enabled", cmd))
|
||||
} else {
|
||||
commandLogger.Info(fmt.Sprintf("%s: Disabled", cmd.Name))
|
||||
commandLogger.Info(fmt.Sprintf("%s: Disabled", cmd))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func sendDisabledCommandMessage(s *Session, cmd config.Command) {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.disabled, cmd.Name))
|
||||
}
|
||||
|
||||
func sendServerChatMessage(s *Session, message string) {
|
||||
// Make the inside of the casted binary
|
||||
bf := byteframe.NewByteFrame()
|
||||
@@ -92,334 +79,6 @@ func sendServerChatMessage(s *Session, message string) {
|
||||
s.QueueSendMHF(castedBin)
|
||||
}
|
||||
|
||||
func parseChatCommand(s *Session, command string) {
|
||||
database, err := db.GetDB()
|
||||
if err != nil {
|
||||
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
||||
}
|
||||
args := strings.Split(command[len(config.GetConfig().CommandPrefix):], " ")
|
||||
switch args[0] {
|
||||
case commands["Ban"].Prefix:
|
||||
if s.isOp() {
|
||||
if len(args) > 1 {
|
||||
var expiry time.Time
|
||||
if len(args) > 2 {
|
||||
var length int
|
||||
var unit string
|
||||
n, err := fmt.Sscanf(args[2], `%d%s`, &length, &unit)
|
||||
if err == nil && n == 2 {
|
||||
switch unit {
|
||||
case "s", "second", "seconds":
|
||||
expiry = time.Now().Add(time.Duration(length) * time.Second)
|
||||
case "m", "mi", "minute", "minutes":
|
||||
expiry = time.Now().Add(time.Duration(length) * time.Minute)
|
||||
case "h", "hour", "hours":
|
||||
expiry = time.Now().Add(time.Duration(length) * time.Hour)
|
||||
case "d", "day", "days":
|
||||
expiry = time.Now().Add(time.Duration(length) * time.Hour * 24)
|
||||
case "mo", "month", "months":
|
||||
expiry = time.Now().Add(time.Duration(length) * time.Hour * 24 * 30)
|
||||
case "y", "year", "years":
|
||||
expiry = time.Now().Add(time.Duration(length) * time.Hour * 24 * 365)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ban.error)
|
||||
return
|
||||
}
|
||||
}
|
||||
cid := mhfcid.ConvertCID(args[1])
|
||||
if cid > 0 {
|
||||
var uid uint32
|
||||
var uname string
|
||||
err := database.QueryRow(`SELECT id, username FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, cid).Scan(&uid, &uname)
|
||||
if err == nil {
|
||||
if expiry.IsZero() {
|
||||
database.Exec(`INSERT INTO bans VALUES ($1)
|
||||
ON CONFLICT (user_id) DO UPDATE SET expires=NULL`, uid)
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.ban.success, uname))
|
||||
} else {
|
||||
database.Exec(`INSERT INTO bans VALUES ($1, $2)
|
||||
ON CONFLICT (user_id) DO UPDATE SET expires=$2`, uid, expiry)
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.ban.success, uname)+fmt.Sprintf(s.Server.i18n.commands.ban.length, expiry.Format(time.DateTime)))
|
||||
}
|
||||
s.Server.DisconnectUser(uid)
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ban.noUser)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ban.invalid)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ban.error)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.noOp)
|
||||
}
|
||||
case commands["Timer"].Prefix:
|
||||
if commands["Timer"].Enabled || s.isOp() {
|
||||
var state bool
|
||||
database.QueryRow(`SELECT COALESCE(timer, false) FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&state)
|
||||
database.Exec(`UPDATE users u SET timer=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, !state, s.CharID)
|
||||
if state {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.timer.disabled)
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.timer.enabled)
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Timer"])
|
||||
}
|
||||
case commands["PSN"].Prefix:
|
||||
if commands["PSN"].Enabled || s.isOp() {
|
||||
if len(args) > 1 {
|
||||
var exists int
|
||||
database.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, args[1]).Scan(&exists)
|
||||
if exists == 0 {
|
||||
_, err := database.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, args[1], s.CharID)
|
||||
if err == nil {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.psn.success, args[1]))
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.psn.exists)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.psn.error, commands["PSN"].Prefix))
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["PSN"])
|
||||
}
|
||||
case commands["Reload"].Prefix:
|
||||
if commands["Reload"].Enabled || s.isOp() {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.reload)
|
||||
var temp mhfpacket.MHFPacket
|
||||
for _, object := range s.stage.objects {
|
||||
if object.ownerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
for _, session := range s.Server.sessions {
|
||||
if s == session {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.CharID}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
for _, session := range s.Server.sessions {
|
||||
if s == session {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysInsertUser{CharID: session.CharID}
|
||||
s.QueueSendMHF(temp)
|
||||
for i := 0; i < 3; i++ {
|
||||
temp = &mhfpacket.MsgSysNotifyUserBinary{
|
||||
CharID: session.CharID,
|
||||
BinaryType: uint8(i + 1),
|
||||
}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
}
|
||||
for _, obj := range s.stage.objects {
|
||||
if obj.ownerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: obj.id,
|
||||
X: obj.x,
|
||||
Y: obj.y,
|
||||
Z: obj.z,
|
||||
Unk0: 0,
|
||||
OwnerCharID: obj.ownerCharID,
|
||||
}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Reload"])
|
||||
}
|
||||
case commands["KeyQuest"].Prefix:
|
||||
if commands["KeyQuest"].Enabled || s.isOp() {
|
||||
if config.GetConfig().ClientID < config.G10 {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.kqf.version)
|
||||
} else {
|
||||
if len(args) > 1 {
|
||||
if args[1] == "get" {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.kqf.get, s.kqf))
|
||||
} else if args[1] == "set" {
|
||||
if len(args) > 2 && len(args[2]) == 16 {
|
||||
hexd, _ := hex.DecodeString(args[2])
|
||||
s.kqf = hexd
|
||||
s.kqfOverride = true
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.kqf.set.success)
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.kqf.set.error, commands["KeyQuest"].Prefix))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["KeyQuest"])
|
||||
}
|
||||
case commands["Rights"].Prefix:
|
||||
if commands["Rights"].Enabled || s.isOp() {
|
||||
if len(args) > 1 {
|
||||
v, _ := strconv.Atoi(args[1])
|
||||
_, err := database.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.CharID)
|
||||
if err == nil {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.rights.success, v))
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.rights.error, commands["Rights"].Prefix))
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.rights.error, commands["Rights"].Prefix))
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Rights"])
|
||||
}
|
||||
case commands["Course"].Prefix:
|
||||
if commands["Course"].Enabled || s.isOp() {
|
||||
if len(args) > 1 {
|
||||
for _, course := range mhfcourse.Courses() {
|
||||
for _, alias := range course.Aliases() {
|
||||
if strings.ToLower(args[1]) == strings.ToLower(alias) {
|
||||
if slices.Contains(config.GetConfig().Courses, config.Course{Name: course.Aliases()[0], Enabled: true}) {
|
||||
var delta, rightsInt uint32
|
||||
if mhfcourse.CourseExists(course.ID, s.courses) {
|
||||
ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool {
|
||||
for _, alias := range c.Aliases() {
|
||||
if strings.ToLower(args[1]) == strings.ToLower(alias) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
if ei != -1 {
|
||||
delta = uint32(-1 * math.Pow(2, float64(course.ID)))
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.disabled, course.Aliases()[0]))
|
||||
}
|
||||
} else {
|
||||
delta = uint32(math.Pow(2, float64(course.ID)))
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.enabled, course.Aliases()[0]))
|
||||
}
|
||||
err := database.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.CharID).Scan(&rightsInt)
|
||||
if err == nil {
|
||||
database.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.CharID)
|
||||
}
|
||||
updateRights(s)
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.locked, course.Aliases()[0]))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.course.error, commands["Course"].Prefix))
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Course"])
|
||||
}
|
||||
case commands["Raviente"].Prefix:
|
||||
if commands["Raviente"].Enabled || s.isOp() {
|
||||
if len(args) > 1 {
|
||||
if s.Server.getRaviSemaphore() != nil {
|
||||
switch args[1] {
|
||||
case "start":
|
||||
if s.Server.raviente.register[1] == 0 {
|
||||
s.Server.raviente.register[1] = s.Server.raviente.register[3]
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.start.success)
|
||||
s.notifyRavi()
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.start.error)
|
||||
}
|
||||
case "cm", "check", "checkmultiplier", "multiplier":
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.ravi.multiplier, s.Server.GetRaviMultiplier()))
|
||||
case "sr", "sendres", "resurrection", "ss", "sendsed", "rs", "reqsed":
|
||||
if config.GetConfig().ClientID == config.ZZ {
|
||||
switch args[1] {
|
||||
case "sr", "sendres", "resurrection":
|
||||
if s.Server.raviente.state[28] > 0 {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.res.success)
|
||||
s.Server.raviente.state[28] = 0
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.res.error)
|
||||
}
|
||||
case "ss", "sendsed":
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.sed.success)
|
||||
// Total BerRavi HP
|
||||
HP := s.Server.raviente.state[0] + s.Server.raviente.state[1] + s.Server.raviente.state[2] + s.Server.raviente.state[3] + s.Server.raviente.state[4]
|
||||
s.Server.raviente.support[1] = HP
|
||||
case "rs", "reqsed":
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.request)
|
||||
// Total BerRavi HP
|
||||
HP := s.Server.raviente.state[0] + s.Server.raviente.state[1] + s.Server.raviente.state[2] + s.Server.raviente.state[3] + s.Server.raviente.state[4]
|
||||
s.Server.raviente.support[1] = HP + 1
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.version)
|
||||
}
|
||||
default:
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.error)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.noPlayers)
|
||||
}
|
||||
} else {
|
||||
sendServerChatMessage(s, s.Server.i18n.commands.ravi.error)
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Raviente"])
|
||||
}
|
||||
case commands["Teleport"].Prefix:
|
||||
if commands["Teleport"].Enabled || s.isOp() {
|
||||
if len(args) > 2 {
|
||||
x, _ := strconv.ParseInt(args[1], 10, 16)
|
||||
y, _ := strconv.ParseInt(args[2], 10, 16)
|
||||
payload := byteframe.NewByteFrame()
|
||||
payload.SetLE()
|
||||
payload.WriteUint8(2) // SetState type(position == 2)
|
||||
payload.WriteInt16(int16(x)) // X
|
||||
payload.WriteInt16(int16(y)) // Y
|
||||
payloadBytes := payload.Data()
|
||||
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
|
||||
CharID: s.CharID,
|
||||
MessageType: BinaryMessageTypeState,
|
||||
RawDataPayload: payloadBytes,
|
||||
})
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.teleport.success, x, y))
|
||||
} else {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.teleport.error, commands["Teleport"].Prefix))
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Teleport"])
|
||||
}
|
||||
case commands["Discord"].Prefix:
|
||||
if commands["Discord"].Enabled || s.isOp() {
|
||||
var _token string
|
||||
err := database.QueryRow(`SELECT discord_token FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.CharID).Scan(&_token)
|
||||
if err != nil {
|
||||
randToken := make([]byte, 4)
|
||||
rand.Read(randToken)
|
||||
_token = fmt.Sprintf("%x-%x", randToken[:2], randToken[2:])
|
||||
database.Exec(`UPDATE users u SET discord_token = $1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, _token, s.CharID)
|
||||
}
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.commands.discord.success, _token))
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Discord"])
|
||||
}
|
||||
case commands["Help"].Prefix:
|
||||
if commands["Help"].Enabled || s.isOp() {
|
||||
for _, command := range commands {
|
||||
if command.Enabled || s.isOp() {
|
||||
sendServerChatMessage(s, fmt.Sprintf("%s%s: %s", config.GetConfig().CommandPrefix, command.Prefix, command.Description))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Help"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysCastBinary)
|
||||
tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
|
||||
@@ -435,7 +94,13 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
_ = tmp.ReadBytes(9)
|
||||
tmp.SetLE()
|
||||
frame := tmp.ReadUint32()
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.Server.i18n.timer, frame/30/60/60, frame/30/60, frame/30%60, int(math.Round(float64(frame%30*100)/3)), frame))
|
||||
s.sendMessage(t("timer", v{
|
||||
"hours": fmt.Sprintf("%d", int(frame/30/60/60)),
|
||||
"minutes": fmt.Sprintf("%d", frame/30/60),
|
||||
"seconds": fmt.Sprintf("%d", frame/30%60),
|
||||
"milliseconds": fmt.Sprintf("%d", int(math.Round(float64(frame%30*100)/3))),
|
||||
"frames": fmt.Sprintf("%d", frame),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,7 +159,10 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
chatMessage := &binpacket.MsgBinChat{}
|
||||
chatMessage.Parse(bf)
|
||||
if strings.HasPrefix(chatMessage.Message, config.GetConfig().CommandPrefix) {
|
||||
parseChatCommand(s, chatMessage.Message)
|
||||
err = executeCommand(s, chatMessage.Message)
|
||||
if err != nil {
|
||||
s.Logger.Error(fmt.Sprintf("Failed to execute command: %s", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
|
||||
|
||||
127
server/channelserver/i18n.go
Normal file
127
server/channelserver/i18n.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"erupe-ce/config"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type v map[string]string
|
||||
|
||||
var translations = map[string]map[string]interface{}{
|
||||
"en": {
|
||||
"language": "English",
|
||||
"cafe.reset": "Resets on {day}/{month}",
|
||||
"timer": "Time: {hours}:{minutes}:{seconds}.{milliseconds} ({frames}f)",
|
||||
"commands.no_op": "You don't have permission to use this command",
|
||||
"commands.disabled": "{command} command is disabled",
|
||||
"commands.reload": "Reloading players...",
|
||||
"commands.kqf.get": "KQF: {kqf}",
|
||||
"commands.kqf.set": "KQF set, please switch Land/World",
|
||||
"commands.kqf.version": "This command is disabled prior to MHFG10",
|
||||
"commands.kqf.error.syntax": "Syntax error, format: {prefix}kqf <get | set xxxxxxxxxxxxxxxx>",
|
||||
"commands.rights.success": "Set rights integer: {rights}",
|
||||
"commands.rights.error.syntax": "Syntax error, format: {prefix}rights <x>",
|
||||
"commands.course.disabled": "{course} Course disabled",
|
||||
"commands.course.enabled": "{course} Course enabled",
|
||||
"commands.course.locked": "{course} Course is locked",
|
||||
"commands.course.error.syntax": "Syntax error, format: {prefix}course <course>",
|
||||
"commands.teleport.success": "Teleporting to {x}, {y}",
|
||||
"commands.teleport.error.syntax": "Syntax error, format: {prefix}tp <x> <y>",
|
||||
"commands.psn.success": "Connected PSN ID: {psn}",
|
||||
"commands.psn.error.exists": "{psn} is connected to another account!",
|
||||
"commands.psn.error.syntax": "Syntax error, format: {prefix}psn <psn id>",
|
||||
"commands.discord.success": "Your Discord token: {token}",
|
||||
"commands.ban.success.permanent": "Successfully banned {username}",
|
||||
"commands.ban.success.temporary": "Successfully banned {username} until {expiry}",
|
||||
"commands.ban.error.invalid": "Invalid Character ID",
|
||||
"commands.ban.error.syntax": "Syntax error, format: {prefix}ban <id> [length]",
|
||||
"commands.timer.enabled": "Quest timer enabled",
|
||||
"commands.timer.disabled": "Quest timer disabled",
|
||||
"commands.ravi.start": "The Great Slaying will begin shortly",
|
||||
"commands.ravi.multiplier": "Raviente multiplier is {multiplier}x",
|
||||
"commands.ravi.resurrect.send": "Sending resurrection support!",
|
||||
"commands.ravi.resurrect.error": "Resurrection support could not be sent",
|
||||
"commands.ravi.sedation.send": "Sending sedation support!",
|
||||
"commands.ravi.sedation.request": "Requesting sedation support!",
|
||||
"commands.ravi.version": "This command is disabled prior to MHFZZ",
|
||||
"commands.ravi.error.start": "The Great Slaying could not be started",
|
||||
"commands.ravi.error.no_players": "No one has joined the Great Slaying!",
|
||||
"commands.ravi.error.syntax": "Syntax error, format: {prefix}ravi <start | multiplier | sr | ss | rs>",
|
||||
"raviente.berserk": "<Great Slaying: Berserk> is being held!",
|
||||
"raviente.extreme": "<Great Slaying: Extreme> is being held!",
|
||||
"raviente.extremelimited": "<Great Slaying: Extreme (Limited)> is being held!",
|
||||
"raviente.berserksmall": "<Great Slaying: Berserk (Small)> is being held!",
|
||||
"guild.invite.invite.title": "Invited!",
|
||||
"guild.invite.invite.body": "You have been invited to join\n「{guild}」\nDo you want to accept?",
|
||||
"guild.invite.success.title": "Success!",
|
||||
"guild.invite.success.body": "You have successfully joined\n「{guild}」.",
|
||||
"guild.invite.accepted.title": "Accepted",
|
||||
"guild.invite.accepted.body": "The invited Hunter has joined\n「{guild}」.",
|
||||
"guild.invite.rejected.title": "Rejected",
|
||||
"guild.invite.rejected.body": "You have rejected the invitation to join\n「{guild}」.",
|
||||
"guild.invite.declined.title": "Declined",
|
||||
"guild.invite.declined.body": "The invited Hunter has declined the invitation to join\n「{guild}」.",
|
||||
},
|
||||
"jp": {
|
||||
"language": "日本語",
|
||||
"cafe.reset": "{day}/{month}にリセット",
|
||||
"timer": "タイマー:{hours}'{minutes}\"{seconds}.{milliseconds} ({frames}f)",
|
||||
"commands.disabled": "{command}のコマンドは無効です",
|
||||
"commands.reload": "リロードします",
|
||||
"commands.kqf.get": "現在のキークエストフラグ:{kqf}",
|
||||
"commands.kqf.set": "キークエストのフラグが更新されました。ワールド/ランドを移動してください",
|
||||
"commands.kqf.error.syntax": "エラー 例:{prefix}kqf set xxxxxxxxxxxxxxxx",
|
||||
"commands.rights.success": "コース情報を更新しました:{rights}",
|
||||
"commands.rights.error.syntax": "エラー 例:{prefix}rights <x>",
|
||||
"commands.course.disabled": "{course}コースは無効です",
|
||||
"commands.course.enabled": "{course}コースは有効です",
|
||||
"commands.course.locked": "{course}コースはロックされています",
|
||||
"commands.course.error.syntax": "エラー 例:{prefix}course <コース>",
|
||||
"commands.teleport.success": "{x} {y}にテレポート",
|
||||
"commands.teleport.error.syntax": "エラー 例:{prefix}teleport <x> <y>",
|
||||
"commands.psn.success": "PSN「{psn}」が連携されています",
|
||||
"commands.psn.error.exists": "{psn}は既存のユーザに接続されています",
|
||||
"commands.psn.error.syntax": "エラー 例:{prefix}psn <PSN>",
|
||||
"commands.discord.success": "あなたのDiscordトークン:{token}",
|
||||
"commands.ban.error.syntax": "エラー 例:{prefix}ban <ID> [期限]",
|
||||
"commands.ravi.start": "大討伐を開始します",
|
||||
"commands.ravi.multiplier": "ラヴィダメージ倍率:x{multiplier}",
|
||||
"commands.ravi.resurrect.send": "復活支援を実行します",
|
||||
"commands.ravi.resurrect.error": "復活支援は実行されませんでした",
|
||||
"commands.ravi.sedation.send": "鎮静支援を実行します",
|
||||
"commands.ravi.sedation.request": "鎮静支援を要請します",
|
||||
"commands.ravi.error.start": "大討伐は既に開催されています",
|
||||
"commands.ravi.error.no_players": "誰も大討伐に参加していません",
|
||||
"commands.ravi.error.syntax": "エラー 例:{prefix}ravi <start | multiplier | sr | ss | rs>",
|
||||
"raviente.berserk": "<大討伐:猛狂期>が開催されました!",
|
||||
"raviente.extreme": "<大討伐:猛狂期【極】>が開催されました!",
|
||||
"raviente.extremelimited": "<大討伐:猛狂期【極】(制限付)>が開催されました!",
|
||||
"raviente.berserksmall": "<大討伐:猛狂期(小数)>が開催されました!",
|
||||
"guild.invite.invite.title": "猟団勧誘のご案内",
|
||||
"guild.invite.invite.body": "猟団「{guild}」からの勧誘通知です。\n「勧誘に返答」より、返答を行ってください。",
|
||||
"guild.invite.success.title": "成功",
|
||||
"guild.invite.success.body": "あなたは「{guild}}」に参加できました。",
|
||||
"guild.invite.accepted.title": "承諾されました",
|
||||
"guild.invite.accepted.body": "招待した狩人が「{guild}}」への招待を承諾しました。",
|
||||
"guild.invite.rejected.title": "却下しました",
|
||||
"guild.invite.rejected.body": "あなたは「{guild}}」への参加を却下しました。",
|
||||
"guild.invite.declined.title": "辞退しました",
|
||||
"guild.invite.declined.body": "招待した狩人が「{guild}}」への招待を辞退しました。",
|
||||
},
|
||||
}
|
||||
|
||||
// t retrieves the translation for a given key and locale
|
||||
func t(key string, placeholders map[string]string) string {
|
||||
// Look for the translation directly
|
||||
if locTranslations, ok := translations[config.GetConfig().Language]; ok {
|
||||
if translation, found := locTranslations[key]; found {
|
||||
str := translation.(string)
|
||||
for placeholder, replacement := range placeholders {
|
||||
str = strings.ReplaceAll(str, "{"+placeholder+"}", replacement)
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
// Fallback to returning the key itself if translation is not found
|
||||
return key
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/binpacket"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"erupe-ce/utils/byteframe"
|
||||
"erupe-ce/utils/db"
|
||||
@@ -251,6 +252,25 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) sendMessage(message string) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
msgBinChat := &binpacket.MsgBinChat{
|
||||
Unk0: 0,
|
||||
Type: 5,
|
||||
Flags: 0x80,
|
||||
Message: message,
|
||||
SenderName: "Erupe",
|
||||
}
|
||||
msgBinChat.Build(bf)
|
||||
castedBin := &mhfpacket.MsgSysCastedBinary{
|
||||
CharID: 0,
|
||||
MessageType: BinaryMessageTypeChat,
|
||||
RawDataPayload: bf.Data(),
|
||||
}
|
||||
s.QueueSendMHF(castedBin)
|
||||
}
|
||||
|
||||
func (s *Session) SetObjectID() {
|
||||
for i := uint16(1); i < 127; i++ {
|
||||
exists := false
|
||||
|
||||
Reference in New Issue
Block a user