mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-03-01 00:35:36 +08:00
命令管理器初步兼容GM
This commit is contained in:
@@ -1,43 +1,56 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"hk4e/gs/model"
|
"hk4e/gs/model"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HelpCommand 帮助命令
|
// HelpCommand 帮助命令
|
||||||
func (c *CommandManager) HelpCommand(cmd *Command) {
|
func (c *CommandManager) HelpCommand(cmd *CommandMessage) {
|
||||||
c.gameManager.SendPrivateChat(c.system, cmd.Executor,
|
executor := cmd.Executor
|
||||||
|
|
||||||
|
c.SendMessage(executor,
|
||||||
"===== 帮助 / Help =====\n"+
|
"===== 帮助 / Help =====\n"+
|
||||||
"以后再写awa\n",
|
"传送: /tp {-u [UID]} {-s [场景ID]} -x [坐标X] -y [坐标Y] -z [坐标Z]\n",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpCommand 给予权限命令
|
// OpCommand 给予权限命令
|
||||||
func (c *CommandManager) OpCommand(cmd *Command) {
|
func (c *CommandManager) OpCommand(cmd *CommandMessage) {
|
||||||
cmd.Executor.IsGM = 1
|
player, ok := cmd.Executor.(*model.Player)
|
||||||
c.gameManager.SendPrivateChat(c.system, cmd.Executor, fmt.Sprintf("权限修改完毕, 现在你是GM啦 %v", cmd.Args))
|
if !ok {
|
||||||
|
c.SendMessage(cmd.Executor, "只有玩家才能执行此命令。")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
player.IsGM = 1
|
||||||
|
c.SendMessage(player, "权限修改完毕, 现在你是GM啦 %v", cmd.Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TeleportCommand 传送玩家命令
|
// TeleportCommand 传送玩家命令
|
||||||
// tp {-u [userId]} {-s [sceneId]} -x [posX] -y [posY] -z [posZ]
|
// tp {-u [userId]} {-s [sceneId]} -x [posX] -y [posY] -z [posZ]
|
||||||
func (c *CommandManager) TeleportCommand(cmd *Command) {
|
func (c *CommandManager) TeleportCommand(cmd *CommandMessage) {
|
||||||
game := c.gameManager
|
game := c.gameManager
|
||||||
player := cmd.Executor
|
|
||||||
|
// 执行者如果不是玩家则必须输入目标UID
|
||||||
|
player, ok := cmd.Executor.(*model.Player)
|
||||||
|
if !ok && cmd.Args["u"] == "" {
|
||||||
|
c.SendMessage(cmd.Executor, "你不是玩家请指定目标UID。")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否填写必备参数
|
||||||
|
if cmd.Args["x"] == "" || cmd.Args["y"] == "" || cmd.Args["z"] == "" {
|
||||||
|
c.SendMessage(player, "参数不足, 正确用法: /%v {-u [UID]} {-s [场景ID]} -x [坐标X] -y [坐标Y] -z [坐标Z]。", cmd.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 初始值
|
// 初始值
|
||||||
target := player
|
target := player
|
||||||
sceneId := target.SceneId
|
sceneId := target.SceneId
|
||||||
pos := &model.Vector{}
|
pos := &model.Vector{}
|
||||||
|
|
||||||
// 判断是否填写必备参数
|
|
||||||
if cmd.Args["x"] == "" || cmd.Args["y"] == "" || cmd.Args["z"] == "" {
|
|
||||||
game.SendPrivateChat(c.system, player, "参数不足, 正确用法 /tp {-u [userId]} {-s [sceneId]} -x [posX] -y [posY] -z [posZ]。")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择每个参数
|
// 选择每个参数
|
||||||
for k, v := range cmd.Args {
|
for k, v := range cmd.Args {
|
||||||
var err error
|
var err error
|
||||||
@@ -47,8 +60,11 @@ func (c *CommandManager) TeleportCommand(cmd *Command) {
|
|||||||
var t uint64
|
var t uint64
|
||||||
if t, err = strconv.ParseUint(v, 10, 32); err != nil {
|
if t, err = strconv.ParseUint(v, 10, 32); err != nil {
|
||||||
// 判断目标用户是否在线
|
// 判断目标用户是否在线
|
||||||
if target = game.userManager.GetOnlineUser(uint32(t)); target == nil {
|
if user := game.userManager.GetOnlineUser(uint32(t)); user != nil {
|
||||||
game.SendPrivateChat(c.system, player, fmt.Sprintf("目标玩家不在线, UID: %v。", v))
|
target = user
|
||||||
|
sceneId = target.SceneId
|
||||||
|
} else {
|
||||||
|
c.SendMessage(player, "目标玩家不在线, UID: %v。", v)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,13 +110,13 @@ func (c *CommandManager) TeleportCommand(cmd *Command) {
|
|||||||
pos.Z = z + nowZ
|
pos.Z = z + nowZ
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
game.SendPrivateChat(c.system, player, fmt.Sprintf("参数 -%v 冗余。", k))
|
c.SendMessage(player, "参数 -%v 冗余。", k)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析错误的话应该是参数类型问题
|
// 解析错误的话应该是参数类型问题
|
||||||
if err != nil {
|
if err != nil {
|
||||||
game.SendPrivateChat(c.system, player, fmt.Sprintf("参数 -%v 有误, 类型错误。", k))
|
c.SendMessage("参数 -%v 有误, 类型错误。", k)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,5 +125,5 @@ func (c *CommandManager) TeleportCommand(cmd *Command) {
|
|||||||
game.TeleportPlayer(target, sceneId, pos)
|
game.TeleportPlayer(target, sceneId, pos)
|
||||||
|
|
||||||
// 发送消息给执行者
|
// 发送消息给执行者
|
||||||
game.SendPrivateChat(c.system, player, fmt.Sprintf("已将玩家 UID: %v 传送至 区域: %v X: %v Y: %v Z:%v。", target.PlayerID, sceneId, pos.X, pos.Y, pos.Z))
|
c.SendMessage(player, "已将玩家 UID: %v 传送至 场景: %v X: %v Y: %v Z:%v。", target.PlayerID, sceneId, pos.X, pos.Y, pos.Z)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// CommandFunc 命令执行函数
|
// CommandFunc 命令执行函数
|
||||||
type CommandFunc func(*Command)
|
type CommandFunc func(*CommandMessage)
|
||||||
|
|
||||||
// Command 命令结构体
|
// CommandMessage 命令消息
|
||||||
// 给下层执行命令时提供数据
|
// 给下层执行命令时提供数据
|
||||||
type Command struct {
|
type CommandMessage struct {
|
||||||
Executor *model.Player // 执行者
|
// executor 玩家为 model.Player 类型
|
||||||
|
// GM等为 string 类型
|
||||||
|
Executor any // 执行者
|
||||||
Text string // 命令原始文本
|
Text string // 命令原始文本
|
||||||
Name string // 命令前缀
|
Name string // 命令前缀
|
||||||
Args map[string]string // 命令参数
|
Args map[string]string // 命令参数
|
||||||
@@ -35,7 +37,7 @@ type CommandManager struct {
|
|||||||
system *model.Player // 机器人 目前负责收发消息 以及 大世界
|
system *model.Player // 机器人 目前负责收发消息 以及 大世界
|
||||||
commandFuncRouter map[string]CommandFunc // 记录命令处理函数
|
commandFuncRouter map[string]CommandFunc // 记录命令处理函数
|
||||||
commandPermMap map[string]CommandPerm // 记录命令对应的权限
|
commandPermMap map[string]CommandPerm // 记录命令对应的权限
|
||||||
commandTextInput chan *Command // 传输要处理的命令文本
|
commandTextInput chan *CommandMessage // 传输要处理的命令文本
|
||||||
|
|
||||||
gameManager *GameManager
|
gameManager *GameManager
|
||||||
}
|
}
|
||||||
@@ -53,7 +55,7 @@ func NewCommandManager(g *GameManager) *CommandManager {
|
|||||||
g.worldManager.InitBigWorld(r.system)
|
g.worldManager.InitBigWorld(r.system)
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
r.commandTextInput = make(chan *Command, 1000)
|
r.commandTextInput = make(chan *CommandMessage, 1000)
|
||||||
r.InitRouter() // 初始化路由
|
r.InitRouter() // 初始化路由
|
||||||
|
|
||||||
r.gameManager = g
|
r.gameManager = g
|
||||||
@@ -105,7 +107,7 @@ func (c *CommandManager) HasCommand(cmdName string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InputCommand 输入要处理的命令
|
// InputCommand 输入要处理的命令
|
||||||
func (c *CommandManager) InputCommand(executor *model.Player, text string) {
|
func (c *CommandManager) InputCommand(executor any, text string) {
|
||||||
// 机器人不会读命令所以写到了 PrivateChatReq
|
// 机器人不会读命令所以写到了 PrivateChatReq
|
||||||
|
|
||||||
// 确保消息文本为 / 开头
|
// 确保消息文本为 / 开头
|
||||||
@@ -113,10 +115,52 @@ func (c *CommandManager) InputCommand(executor *model.Player, text string) {
|
|||||||
if strings.HasPrefix(text, "/") {
|
if strings.HasPrefix(text, "/") {
|
||||||
|
|
||||||
// 输入的命令将在其他协程中处理
|
// 输入的命令将在其他协程中处理
|
||||||
c.commandTextInput <- c.NewCommand(executor, text)
|
c.commandTextInput <- &CommandMessage{Executor: executor, Text: text}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleCommand 处理命令
|
||||||
|
// 主协程接收到命令消息后执行
|
||||||
|
func (c *CommandManager) HandleCommand(cmd *CommandMessage) {
|
||||||
|
// 将开头的 / 去掉 并 分割出命令的每个参数
|
||||||
|
// 不区分命令的大小写 统一转为小写
|
||||||
|
cmdSplit := strings.Split(strings.ToLower(cmd.Text[1:]), " -")
|
||||||
|
|
||||||
|
// 分割出来啥也没有可能是个空的字符串
|
||||||
|
// 此时将会返回的命令名和命令参数都为空
|
||||||
|
if len(cmdSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命令参数 初始化
|
||||||
|
cmd.Args = make(map[string]string, len(cmdSplit)-1)
|
||||||
|
|
||||||
|
// 首个参数必是命令名
|
||||||
|
cmd.Name = cmdSplit[0]
|
||||||
|
// 命令名后当然是命令的参数喽
|
||||||
|
argSplit := cmdSplit[1:]
|
||||||
|
|
||||||
|
// 我们要将命令的参数转换为键值对
|
||||||
|
// 每个参数之间会有个空格分割
|
||||||
|
for _, s := range argSplit {
|
||||||
|
cmdArg := strings.Split(s, " ")
|
||||||
|
|
||||||
|
// 分割出来的参数只有一个那肯定不是键值对
|
||||||
|
if len(cmdArg) < 2 {
|
||||||
|
logger.LOG.Debug("command arg error, arg: %v", cmdArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
argKey := cmdArg[0] // 参数的键
|
||||||
|
argValue := cmdArg[1] // 参数的值
|
||||||
|
|
||||||
|
// 记录命令的参数
|
||||||
|
cmd.Args[argKey] = argValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行命令
|
||||||
|
c.ExecCommand(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
// GetFriendList 获取包含系统的玩家好友列表
|
// GetFriendList 获取包含系统的玩家好友列表
|
||||||
func (c *CommandManager) GetFriendList(friendList map[uint32]bool) map[uint32]bool {
|
func (c *CommandManager) GetFriendList(friendList map[uint32]bool) map[uint32]bool {
|
||||||
// 可能还有更好的方法实现这功能
|
// 可能还有更好的方法实现这功能
|
||||||
@@ -134,54 +178,16 @@ func (c *CommandManager) GetFriendList(friendList map[uint32]bool) map[uint32]bo
|
|||||||
return tempFriendList
|
return tempFriendList
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommand 创建命令结构
|
|
||||||
func (c *CommandManager) NewCommand(executor *model.Player, text string) *Command {
|
|
||||||
// 将开头的 / 去掉 并 分割出命令的每个参数
|
|
||||||
// 不区分命令的大小写 统一转为小写
|
|
||||||
cmdSplit := strings.Split(strings.ToLower(text[1:]), " -")
|
|
||||||
|
|
||||||
cmdName := "" // 命令名
|
|
||||||
cmdArgs := make(map[string]string, len(cmdSplit)-1) // 命令参数
|
|
||||||
|
|
||||||
// 分割出来啥也没有可能是个空的字符串
|
|
||||||
// 此时将会返回的命令名和命令参数都为空
|
|
||||||
if len(cmdSplit) != 0 {
|
|
||||||
// 首个参数必是命令名
|
|
||||||
cmdName = cmdSplit[0]
|
|
||||||
// 命令名后当然是命令的参数喽
|
|
||||||
argSplit := cmdSplit[1:]
|
|
||||||
|
|
||||||
// 我们要将命令的参数转换为键值对
|
|
||||||
// 每个参数之间会有个空格分割
|
|
||||||
for _, s := range argSplit {
|
|
||||||
cmdArg := strings.Split(s, " ")
|
|
||||||
|
|
||||||
// 分割出来的参数只有一个那肯定不是键值对
|
|
||||||
if len(cmdArg) >= 2 {
|
|
||||||
argKey := cmdArg[0] // 参数的键
|
|
||||||
argValue := cmdArg[1] // 参数的值
|
|
||||||
|
|
||||||
// 记录命令的参数
|
|
||||||
cmdArgs[argKey] = argValue
|
|
||||||
} else {
|
|
||||||
logger.LOG.Debug("command arg error, arg: %v", cmdArg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Command{executor, text, cmdName, cmdArgs}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecCommand 执行命令
|
// ExecCommand 执行命令
|
||||||
func (c *CommandManager) ExecCommand(cmd *Command) {
|
func (c *CommandManager) ExecCommand(cmd *CommandMessage) {
|
||||||
player := cmd.Executor
|
executor := cmd.Executor
|
||||||
|
|
||||||
// 判断命令是否注册
|
// 判断命令是否注册
|
||||||
cmdFunc, ok := c.commandFuncRouter[cmd.Name]
|
cmdFunc, ok := c.commandFuncRouter[cmd.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
// 玩家可能会执行一些没有的命令仅做调试输出
|
// 玩家可能会执行一些没有的命令仅做调试输出
|
||||||
logger.LOG.Debug("exec command not exist, name: %v", cmd.Name)
|
logger.LOG.Debug("exec command not exist, name: %v", cmd.Name)
|
||||||
c.gameManager.SendPrivateChat(c.system, player, "命令不存在,输入 /help 查看帮助。")
|
c.SendMessage(executor, "命令不存在,输入 /help 查看帮助。")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 判断命令权限是否注册
|
// 判断命令权限是否注册
|
||||||
@@ -192,14 +198,35 @@ func (c *CommandManager) ExecCommand(cmd *Command) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 执行者是否为玩家
|
||||||
|
player, ok := executor.(*model.Player)
|
||||||
// 判断玩家的权限是否符合要求
|
// 判断玩家的权限是否符合要求
|
||||||
if player.IsGM < uint8(cmdPerm) {
|
if ok && player.IsGM < uint8(cmdPerm) {
|
||||||
logger.LOG.Debug("exec command permission denied, uid: %v, isGM: %v", player.PlayerID, player.IsGM)
|
logger.LOG.Debug("exec command permission denied, uid: %v, isGM: %v", player.PlayerID, player.IsGM)
|
||||||
c.gameManager.SendPrivateChat(c.system, player, fmt.Sprintf("权限不足,该命令需要%v级权限。\n你目前的权限等级:%v", cmdPerm, player.IsGM))
|
c.SendMessage(player, "权限不足,该命令需要%v级权限。\n你目前的权限等级:%v", cmdPerm, player.IsGM)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LOG.Debug("command start, uid: %v, text: %v, name: %v, args: %v", cmd.Executor.PlayerID, cmd.Text, cmd.Name, cmd.Args)
|
logger.LOG.Debug("command start, name: %v, args: $v", cmd.Name, cmd.Args)
|
||||||
cmdFunc(cmd) // 执行命令
|
cmdFunc(cmd) // 执行命令
|
||||||
logger.LOG.Debug("command done, uid: %v, text: %v, name: %v, args: %v", cmd.Executor.PlayerID, cmd.Text, cmd.Name, cmd.Args)
|
logger.LOG.Debug("command done, name: %v, args: $v", cmd.Name, cmd.Args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMessage 发送消息
|
||||||
|
func (c *CommandManager) SendMessage(executor any, msg string, param ...any) {
|
||||||
|
game := c.gameManager
|
||||||
|
|
||||||
|
// 根据相应的类型发送消息
|
||||||
|
switch executor.(type) {
|
||||||
|
case *model.Player:
|
||||||
|
// 玩家类型
|
||||||
|
player := executor.(*model.Player)
|
||||||
|
game.SendPrivateChat(c.system, player, fmt.Sprintf(msg, param...))
|
||||||
|
case string:
|
||||||
|
// GM接口等
|
||||||
|
//str := executor.(string)
|
||||||
|
default:
|
||||||
|
// 无效的类型报错
|
||||||
|
logger.LOG.Error("command executor type error, type: %T", executor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (g *GameManager) Start() {
|
|||||||
g.localEventManager.LocalEventHandle(localEvent)
|
g.localEventManager.LocalEventHandle(localEvent)
|
||||||
case command := <-g.commandManager.commandTextInput:
|
case command := <-g.commandManager.commandTextInput:
|
||||||
// 处理传入的命令 (普通玩家 GM命令)
|
// 处理传入的命令 (普通玩家 GM命令)
|
||||||
g.commandManager.ExecCommand(command)
|
g.commandManager.HandleCommand(command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
Reference in New Issue
Block a user