传送命令,命令管理器完善

This commit is contained in:
UnKownOwO
2022-11-25 15:45:38 +08:00
parent 85f5ed1c96
commit 71a1f20f8a
3 changed files with 203 additions and 92 deletions

View File

@@ -1,6 +1,11 @@
package game
import "fmt"
import (
"fmt"
"hk4e/gs/model"
"strconv"
"strings"
)
// HelpCommand 帮助命令
func (c *CommandManager) HelpCommand(cmd *Command) {
@@ -10,8 +15,99 @@ func (c *CommandManager) HelpCommand(cmd *Command) {
)
}
// OpCommand 帮助命令
// OpCommand 给予权限命令
func (c *CommandManager) OpCommand(cmd *Command) {
cmd.Executor.IsGM = 1
c.gameManager.SendPrivateChat(c.system, cmd.Executor, fmt.Sprintf("权限修改完毕, 现在你是GM啦 %v", cmd.Args))
}
// TeleportCommand 传送玩家命令
// tp {-u [userId]} {-s [sceneId]} -x [posX] -y [posY] -z [posZ]
func (c *CommandManager) TeleportCommand(cmd *Command) {
game := c.gameManager
player := cmd.Executor
// 初始值
target := player
sceneId := target.SceneId
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 {
var err error
switch k {
case "u":
var t uint64
if t, err = strconv.ParseUint(v, 10, 32); err != nil {
// 判断目标用户是否在线
if target = game.userManager.GetOnlineUser(uint32(t)); target == nil {
game.SendPrivateChat(c.system, player, fmt.Sprintf("目标玩家不在线, UID: %v。", v))
return
}
}
case "s":
var s uint64
if s, err = strconv.ParseUint(v, 10, 32); err == nil {
sceneId = uint32(s)
}
case "x":
// 玩家此时的位置X
var nowX float64
// 如果以 ~ 开头则 此时位置加 ~ 后的数
if strings.HasPrefix(v, "~") {
v = v[1:] // 去除 ~
nowX = player.Pos.X // 先记录
}
var x float64
if x, err = strconv.ParseFloat(v, 64); err == nil {
pos.X = x + nowX // 如果不以 ~ 开头则加 0
}
case "y":
// 玩家此时的位置Z
var nowY float64
// 如果以 ~ 开头则 此时位置加 ~ 后的数
if strings.HasPrefix(v, "~") {
v = v[1:] // 去除 ~
nowY = player.Pos.Y // 先记录
}
var y float64
if y, err = strconv.ParseFloat(v, 64); v != "~" && err == nil {
pos.Y = y + nowY
}
case "z":
// 玩家此时的位置Z
var nowZ float64
// 如果以 ~ 开头则 此时位置加 ~ 后的数
if strings.HasPrefix(v, "~") {
v = v[1:] // 去除 ~
nowZ = player.Pos.Z // 先记录
}
var z float64
if z, err = strconv.ParseFloat(v, 64); v != "~" && err == nil {
pos.Z = z + nowZ
}
default:
game.SendPrivateChat(c.system, player, fmt.Sprintf("参数 -%v 冗余。", k))
return
}
// 解析错误的话应该是参数类型问题
if err != nil {
game.SendPrivateChat(c.system, player, fmt.Sprintf("参数 -%v 有误, 类型错误。", k))
return
}
}
// 传送玩家
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))
}

View File

@@ -13,16 +13,21 @@ import (
// 0 为普通玩家 数越大权限越大
type CommandPerm uint8
const (
CommandPermNormal = CommandPerm(iota) // 普通玩家
CommandPermGM // 管理员
)
// CommandFunc 命令执行函数
type CommandFunc func(*Command)
// Command 命令结构体
// 给下层执行命令时提供数据
type Command struct {
Executor *model.Player // 执行者
Text string // 命令原始文本
Name string // 命令前缀
Args []string // 命令参数
Executor *model.Player // 执行者
Text string // 命令原始文本
Name string // 命令前缀
Args map[string]string // 命令参数
}
// CommandManager 命令管理器
@@ -61,23 +66,42 @@ func (c *CommandManager) InitRouter() {
c.commandPermMap = make(map[string]CommandPerm)
{
// 权限等级 0: 普通玩家
c.RegisterRouter("help", 0, c.HelpCommand)
c.RegisterRouter("op", 0, c.OpCommand)
c.RegisterRouter(CommandPermNormal, c.HelpCommand, "help")
c.RegisterRouter(CommandPermNormal, c.OpCommand, "op")
c.RegisterRouter(CommandPermNormal, c.TeleportCommand, "teleport", "tp")
}
// GM命令
{
// 权限等级 1: GM 1级
c.RegisterRouter("nmsl", 1, c.HelpCommand)
c.RegisterRouter(CommandPermGM, c.HelpCommand, "nmsl")
}
}
// RegisterRouter 注册命令路由
func (c *CommandManager) RegisterRouter(cmdName string, cmdPerm CommandPerm, cmdFunc CommandFunc) {
// 命令名统一转为小写
cmdName = strings.ToLower(cmdName)
// 记录命令
c.commandFuncRouter[cmdName] = cmdFunc
c.commandPermMap[cmdName] = cmdPerm
func (c *CommandManager) RegisterRouter(cmdPerm CommandPerm, cmdFunc CommandFunc, cmdName ...string) {
// 支持一个命令拥有多个别名
for _, s := range cmdName {
// 命令名统一转为小写
s = strings.ToLower(s)
// 如果命令已注册则报错 后者覆盖前者
if c.HasCommand(s) {
logger.LOG.Error("register command repeat, name: %v", s)
}
// 记录命令
c.commandFuncRouter[s] = cmdFunc
c.commandPermMap[s] = cmdPerm
}
}
// HasCommand 命令是否已被注册
func (c *CommandManager) HasCommand(cmdName string) bool {
_, cmdFuncOK := c.commandFuncRouter[cmdName]
_, cmdPermOK := c.commandPermMap[cmdName]
// 判断命令函数和命令权限是否已注册
if cmdFuncOK && cmdPermOK {
return true
}
return false
}
// InputCommand 输入要处理的命令
@@ -114,10 +138,10 @@ func (c *CommandManager) GetFriendList(friendList map[uint32]bool) map[uint32]bo
func (c *CommandManager) NewCommand(executor *model.Player, text string) *Command {
// 将开头的 / 去掉 并 分割出命令的每个参数
// 不区分命令的大小写 统一转为小写
cmdSplit := strings.Split(strings.ToLower(text[1:]), " ")
cmdSplit := strings.Split(strings.ToLower(text[1:]), " -")
var cmdName string // 命令名
var cmdArgs []string // 命令参数
cmdName := "" // 命令名
cmdArgs := make(map[string]string, len(cmdSplit)-1) // 命令参数
// 分割出来啥也没有可能是个空的字符串
// 此时将会返回的命令名和命令参数都为空
@@ -125,7 +149,24 @@ func (c *CommandManager) NewCommand(executor *model.Player, text string) *Comman
// 首个参数必是命令名
cmdName = cmdSplit[0]
// 命令名后当然是命令的参数喽
cmdArgs = cmdSplit[1:]
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}

View File

@@ -28,7 +28,50 @@ func (g *GameManager) SceneTransToPointReq(player *model.Player, payloadMsg pb.M
}
// 传送玩家
newSceneId := req.SceneId
sceneId := uint32(transPointConfig.PointData.TranSceneId)
transPos := transPointConfig.PointData.TranPos
pos := &model.Vector{
X: transPos.X,
Y: transPos.Y,
Z: transPos.Z,
}
g.TeleportPlayer(player, sceneId, pos)
// PacketSceneTransToPointRsp
sceneTransToPointRsp := new(proto.SceneTransToPointRsp)
sceneTransToPointRsp.Retcode = 0
sceneTransToPointRsp.PointId = req.PointId
sceneTransToPointRsp.SceneId = req.SceneId
g.SendMsg(cmd.SceneTransToPointRsp, player.PlayerID, player.ClientSeq, sceneTransToPointRsp)
}
func (g *GameManager) MarkMapReq(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user mark map, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.MarkMapReq)
operation := req.Op
if operation == proto.MarkMapReq_OPERATION_ADD {
logger.LOG.Debug("user mark type: %v", req.Mark.PointType)
if req.Mark.PointType == proto.MapMarkPointType_MAP_MARK_POINT_TYPE_NPC {
posYInt, err := strconv.ParseInt(req.Mark.Name, 10, 64)
if err != nil {
logger.LOG.Error("parse pos y error: %v", err)
posYInt = 300
}
// 传送玩家
pos := &model.Vector{
X: float64(req.Mark.Pos.X),
Y: float64(posYInt),
Z: float64(req.Mark.Pos.Z),
}
g.TeleportPlayer(player, req.Mark.SceneId, pos)
}
}
}
// TeleportPlayer 传送玩家至地图上的某个位置
func (g *GameManager) TeleportPlayer(player *model.Player, sceneId uint32, pos *model.Vector) {
// 传送玩家
newSceneId := sceneId
oldSceneId := player.SceneId
oldPos := &model.Vector{
X: player.Pos.X,
@@ -55,9 +98,9 @@ func (g *GameManager) SceneTransToPointReq(player *model.Player, payloadMsg pb.M
} else {
oldScene.UpdatePlayerTeamEntity(player)
}
player.Pos.X = transPointConfig.PointData.TranPos.X
player.Pos.Y = transPointConfig.PointData.TranPos.Y
player.Pos.Z = transPointConfig.PointData.TranPos.Z
player.Pos.X = pos.X
player.Pos.Y = pos.Y
player.Pos.Z = pos.Z
player.SceneId = newSceneId
player.SceneLoadState = model.SceneNone
@@ -72,75 +115,6 @@ func (g *GameManager) SceneTransToPointReq(player *model.Player, payloadMsg pb.M
}
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyTp(player, enterType, uint32(constant.EnterReasonConst.TransPoint), oldSceneId, oldPos)
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
// PacketSceneTransToPointRsp
sceneTransToPointRsp := new(proto.SceneTransToPointRsp)
sceneTransToPointRsp.Retcode = 0
sceneTransToPointRsp.PointId = req.PointId
sceneTransToPointRsp.SceneId = req.SceneId
g.SendMsg(cmd.SceneTransToPointRsp, player.PlayerID, player.ClientSeq, sceneTransToPointRsp)
}
func (g *GameManager) MarkMapReq(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user mark map, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.MarkMapReq)
operation := req.Op
if operation == proto.MarkMapReq_OPERATION_ADD {
logger.LOG.Debug("user mark type: %v", req.Mark.PointType)
if req.Mark.PointType == proto.MapMarkPointType_MAP_MARK_POINT_TYPE_NPC {
posYInt, err := strconv.ParseInt(req.Mark.Name, 10, 64)
if err != nil {
logger.LOG.Error("parse pos y error: %v", err)
posYInt = 300
}
// 传送玩家
newSceneId := req.Mark.SceneId
oldSceneId := player.SceneId
oldPos := &model.Vector{
X: player.Pos.X,
Y: player.Pos.Y,
Z: player.Pos.Z,
}
jumpScene := false
if newSceneId != oldSceneId {
jumpScene = true
}
world := g.worldManager.GetWorldByID(player.WorldId)
oldScene := world.GetSceneById(oldSceneId)
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
playerTeamEntity := oldScene.GetPlayerTeamEntity(player.PlayerID)
g.RemoveSceneEntityNotifyBroadcast(oldScene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
if jumpScene {
// PacketDelTeamEntityNotify
delTeamEntityNotify := g.PacketDelTeamEntityNotify(oldScene, player)
g.SendMsg(cmd.DelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
oldScene.RemovePlayer(player)
newScene := world.GetSceneById(newSceneId)
newScene.AddPlayer(player)
} else {
oldScene.UpdatePlayerTeamEntity(player)
}
player.Pos.X = float64(req.Mark.Pos.X)
player.Pos.Y = float64(posYInt)
player.Pos.Z = float64(req.Mark.Pos.Z)
player.SceneId = newSceneId
player.SceneLoadState = model.SceneNone
// PacketPlayerEnterSceneNotify
var enterType proto.EnterType
if jumpScene {
logger.LOG.Debug("player jump scene, scene: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_TYPE_JUMP
} else {
logger.LOG.Debug("player goto scene, scene: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_TYPE_GOTO
}
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyTp(player, enterType, uint32(constant.EnterReasonConst.TransPoint), oldSceneId, oldPos)
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
}
}
}
func (g *GameManager) PathfindingEnterSceneReq(player *model.Player, payloadMsg pb.Message) {