mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-14 07:55:33 +01:00
422 lines
12 KiB
Go
422 lines
12 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"erupe-ce/config"
|
|
"erupe-ce/internal/constant"
|
|
"erupe-ce/network/mhfpacket"
|
|
"erupe-ce/utils/byteframe"
|
|
"erupe-ce/utils/database"
|
|
"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 {
|
|
db, err := database.GetDB()
|
|
if err != nil {
|
|
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
}
|
|
|
|
if !s.isOp() {
|
|
s.sendMessage(t("commands.no_op", v{}))
|
|
return nil
|
|
}
|
|
|
|
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 = db.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() {
|
|
db.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 {
|
|
db.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 {
|
|
db, err := database.GetDB()
|
|
if err != nil {
|
|
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
}
|
|
var state bool
|
|
db.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)
|
|
db.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 {
|
|
db, err := database.GetDB()
|
|
if err != nil {
|
|
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
}
|
|
if len(args) < 1 {
|
|
s.sendMessage(t("commands.psn.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
|
return nil
|
|
}
|
|
|
|
var exists int
|
|
db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, args[1]).Scan(&exists)
|
|
if exists == 0 {
|
|
_, err := db.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.QueueSendMHFLazy(temp)
|
|
}
|
|
for _, session := range s.Server.sessions {
|
|
if s == session {
|
|
continue
|
|
}
|
|
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.CharID}
|
|
s.QueueSendMHFLazy(temp)
|
|
}
|
|
time.Sleep(500 * time.Millisecond)
|
|
for _, session := range s.Server.sessions {
|
|
if s == session {
|
|
continue
|
|
}
|
|
temp = &mhfpacket.MsgSysInsertUser{CharID: session.CharID}
|
|
s.QueueSendMHFLazy(temp)
|
|
for i := 0; i < 3; i++ {
|
|
temp = &mhfpacket.MsgSysNotifyUserBinary{
|
|
CharID: session.CharID,
|
|
BinaryType: uint8(i + 1),
|
|
}
|
|
s.QueueSendMHFLazy(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.QueueSendMHFLazy(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 {
|
|
db, err := database.GetDB()
|
|
if err != nil {
|
|
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
}
|
|
if len(args) < 1 {
|
|
s.sendMessage(t("commands.rights.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
|
return nil
|
|
}
|
|
|
|
r, _ := strconv.Atoi(args[0])
|
|
_, err = db.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 {
|
|
db, err := database.GetDB()
|
|
if err != nil {
|
|
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
}
|
|
if len(args) < 1 {
|
|
s.sendMessage(t("commands.course.error.syntax", v{"prefix": config.GetConfig().CommandPrefix}))
|
|
return nil
|
|
}
|
|
|
|
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 := 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)
|
|
if err != nil {
|
|
return err
|
|
} else {
|
|
_, err = db.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.QueueSendMHFLazy(&mhfpacket.MsgSysCastedBinary{
|
|
CharID: s.CharID,
|
|
MessageType: constant.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 {
|
|
db, err := database.GetDB()
|
|
if err != nil {
|
|
s.Logger.Fatal(fmt.Sprintf("Failed to get database instance: %s", err))
|
|
}
|
|
var _token string
|
|
err = db.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 = db.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)
|
|
}
|
|
}
|