From cd922d1a38f1fdd4dbf1cd44be2c2d4f0a4cc80c Mon Sep 17 00:00:00 2001 From: flswld Date: Tue, 14 Mar 2023 18:30:07 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BD=91=E5=85=B3=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E4=BB=A3=E7=90=86=E5=8A=9F=E8=83=BD=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=E4=BA=8C=E7=BA=A7pb=E6=95=B0=E6=8D=AE=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gate/net/proto_endecode.go | 141 ++++++++++++++++++++++++++++++++++ gdconf/item_data.go | 4 +- gs/dao/player_mongo.go | 2 +- gs/game/command_controller.go | 40 +++++----- gs/game/command_gm.go | 70 +++++++++-------- gs/game/command_manager.go | 123 ++++++++++++++++++++++++++--- gs/game/player_fight_sync.go | 2 - gs/game/player_reliquary.go | 4 + gs/game/player_weapon.go | 4 + gs/model/db_reliquary.go | 9 +-- gs/model/db_weapon.go | 9 +-- 11 files changed, 331 insertions(+), 77 deletions(-) diff --git a/gate/net/proto_endecode.go b/gate/net/proto_endecode.go index 9e87b816..9862cf8a 100644 --- a/gate/net/proto_endecode.go +++ b/gate/net/proto_endecode.go @@ -64,6 +64,7 @@ func ProtoDecode(kcpMsg *KcpMsg, if len(delList) != 0 { logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName) } + ConvClientPbDataToServer(serverProtoObj, clientCmdProtoMap) serverProtoData, err := pb.Marshal(serverProtoObj) if err != nil { logger.Error("marshal server proto error: %v", err) @@ -175,6 +176,7 @@ func ProtoDecodePayloadLoop(cmdId uint16, protoData []byte, protoMessageList *[] if len(delList) != 0 { logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName) } + ConvClientPbDataToServer(serverProtoObj, clientCmdProtoMap) serverProtoData, err := pb.Marshal(serverProtoObj) if err != nil { logger.Error("marshal server proto error: %v", err) @@ -257,6 +259,7 @@ func ProtoEncode(protoMsg *ProtoMsg, if len(delList) != 0 { logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName) } + ConvServerPbDataToClient(clientProtoObj, clientCmdProtoMap) clientProtoData, err := pb.Marshal(clientProtoObj) if err != nil { logger.Error("marshal client proto error: %v", err) @@ -297,8 +300,14 @@ func EncodeProtoToPayload(protoObj pb.Message, serverCmdProtoMap *cmd.CmdProtoMa return protoData } +// 网关客户端协议代理相关反射方法 + func GetClientProtoObjByName(protoObjName string, clientCmdProtoMap *client_proto.ClientCmdProtoMap) pb.Message { fn := clientCmdProtoMap.RefValue.MethodByName("GetClientProtoObjByName") + if !fn.IsValid() { + logger.Error("fn is nil") + return nil + } ret := fn.Call([]reflect.Value{reflect.ValueOf(protoObjName)}) obj := ret[0].Interface() if obj == nil { @@ -308,3 +317,135 @@ func GetClientProtoObjByName(protoObjName string, clientCmdProtoMap *client_prot clientProtoObj := obj.(pb.Message) return clientProtoObj } + +func ConvClientPbDataToServerCore(protoObjName string, serverProtoObj pb.Message, clientProtoData *[]byte, clientCmdProtoMap *client_proto.ClientCmdProtoMap) { + clientProtoObj := GetClientProtoObjByName(protoObjName, clientCmdProtoMap) + if clientProtoObj == nil { + return + } + err := pb.Unmarshal(*clientProtoData, clientProtoObj) + if err != nil { + return + } + _, err = object.CopyProtoBufSameField(serverProtoObj, clientProtoObj) + if err != nil { + return + } + serverProtoData, err := pb.Marshal(serverProtoObj) + if err != nil { + return + } + *clientProtoData = serverProtoData +} + +func ConvServerPbDataToClientCore(protoObjName string, serverProtoObj pb.Message, serverProtoData *[]byte, clientCmdProtoMap *client_proto.ClientCmdProtoMap) { + err := pb.Unmarshal(*serverProtoData, serverProtoObj) + if err != nil { + return + } + clientProtoObj := GetClientProtoObjByName(protoObjName, clientCmdProtoMap) + if clientProtoObj == nil { + return + } + _, err = object.CopyProtoBufSameField(clientProtoObj, serverProtoObj) + if err != nil { + return + } + clientProtoData, err := pb.Marshal(clientProtoObj) + if err != nil { + return + } + *serverProtoData = clientProtoData +} + +// 在GS侧进行pb.Unmarshal解析二级pb数据前 请先在这里添加相关代码 + +func ConvClientPbDataToServer(protoObj pb.Message, clientCmdProtoMap *client_proto.ClientCmdProtoMap) pb.Message { + switch protoObj.(type) { + case *proto.CombatInvocationsNotify: + ntf := protoObj.(*proto.CombatInvocationsNotify) + for _, entry := range ntf.InvokeList { + switch entry.ArgumentType { + case proto.CombatTypeArgument_COMBAT_EVT_BEING_HIT: + serverProtoObj := new(proto.EvtBeingHitInfo) + ConvClientPbDataToServerCore("EvtBeingHitInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + case proto.CombatTypeArgument_ENTITY_MOVE: + serverProtoObj := new(proto.EntityMoveInfo) + ConvClientPbDataToServerCore("EntityMoveInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + case proto.CombatTypeArgument_COMBAT_ANIMATOR_PARAMETER_CHANGED: + serverProtoObj := new(proto.EvtAnimatorParameterInfo) + ConvClientPbDataToServerCore("EvtAnimatorParameterInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + case proto.CombatTypeArgument_COMBAT_ANIMATOR_STATE_CHANGED: + serverProtoObj := new(proto.EvtAnimatorStateChangedInfo) + ConvClientPbDataToServerCore("EvtAnimatorStateChangedInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + } + } + case *proto.AbilityInvocationsNotify: + ntf := protoObj.(*proto.AbilityInvocationsNotify) + for _, entry := range ntf.Invokes { + switch entry.ArgumentType { + case proto.AbilityInvokeArgument_ABILITY_MIXIN_COST_STAMINA: + serverProtoObj := new(proto.AbilityMixinCostStamina) + ConvClientPbDataToServerCore("AbilityMixinCostStamina", serverProtoObj, &entry.AbilityData, clientCmdProtoMap) + } + } + case *proto.ClientAbilityChangeNotify: + ntf := protoObj.(*proto.ClientAbilityChangeNotify) + for _, entry := range ntf.Invokes { + switch entry.ArgumentType { + case proto.AbilityInvokeArgument_ABILITY_META_ADD_NEW_ABILITY: + serverProtoObj := new(proto.AbilityMetaAddAbility) + ConvClientPbDataToServerCore("AbilityMetaAddAbility", serverProtoObj, &entry.AbilityData, clientCmdProtoMap) + case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE: + serverProtoObj := new(proto.AbilityMetaModifierChange) + ConvClientPbDataToServerCore("AbilityMetaModifierChange", serverProtoObj, &entry.AbilityData, clientCmdProtoMap) + } + } + } + return protoObj +} + +func ConvServerPbDataToClient(protoObj pb.Message, clientCmdProtoMap *client_proto.ClientCmdProtoMap) pb.Message { + switch protoObj.(type) { + case *proto.CombatInvocationsNotify: + ntf := protoObj.(*proto.CombatInvocationsNotify) + for _, entry := range ntf.InvokeList { + switch entry.ArgumentType { + case proto.CombatTypeArgument_COMBAT_EVT_BEING_HIT: + serverProtoObj := new(proto.EvtBeingHitInfo) + ConvServerPbDataToClientCore("EvtBeingHitInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + case proto.CombatTypeArgument_ENTITY_MOVE: + serverProtoObj := new(proto.EntityMoveInfo) + ConvServerPbDataToClientCore("EntityMoveInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + case proto.CombatTypeArgument_COMBAT_ANIMATOR_PARAMETER_CHANGED: + serverProtoObj := new(proto.EvtAnimatorParameterInfo) + ConvServerPbDataToClientCore("EvtAnimatorParameterInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + case proto.CombatTypeArgument_COMBAT_ANIMATOR_STATE_CHANGED: + serverProtoObj := new(proto.EvtAnimatorStateChangedInfo) + ConvServerPbDataToClientCore("EvtAnimatorStateChangedInfo", serverProtoObj, &entry.CombatData, clientCmdProtoMap) + } + } + case *proto.AbilityInvocationsNotify: + ntf := protoObj.(*proto.AbilityInvocationsNotify) + for _, entry := range ntf.Invokes { + switch entry.ArgumentType { + case proto.AbilityInvokeArgument_ABILITY_MIXIN_COST_STAMINA: + serverProtoObj := new(proto.AbilityMixinCostStamina) + ConvServerPbDataToClientCore("AbilityMixinCostStamina", serverProtoObj, &entry.AbilityData, clientCmdProtoMap) + } + } + case *proto.ClientAbilityChangeNotify: + ntf := protoObj.(*proto.ClientAbilityChangeNotify) + for _, entry := range ntf.Invokes { + switch entry.ArgumentType { + case proto.AbilityInvokeArgument_ABILITY_META_ADD_NEW_ABILITY: + serverProtoObj := new(proto.AbilityMetaAddAbility) + ConvServerPbDataToClientCore("AbilityMetaAddAbility", serverProtoObj, &entry.AbilityData, clientCmdProtoMap) + case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE: + serverProtoObj := new(proto.AbilityMetaModifierChange) + ConvServerPbDataToClientCore("AbilityMetaModifierChange", serverProtoObj, &entry.AbilityData, clientCmdProtoMap) + } + } + } + return protoObj +} diff --git a/gdconf/item_data.go b/gdconf/item_data.go index 276c6994..bbbec232 100644 --- a/gdconf/item_data.go +++ b/gdconf/item_data.go @@ -11,9 +11,9 @@ import ( "github.com/jszwec/csvutil" ) -// ItemData 统一道具配置表 +// ItemData 道具分类分表整合配置表 type ItemData struct { - // 公共字段 + // 公共表头字段 ItemId int32 `csv:"ItemId"` // ID Type int32 `csv:"Type,omitempty"` // 类型 Weight int32 `csv:"Weight,omitempty"` // 重量 diff --git a/gs/dao/player_mongo.go b/gs/dao/player_mongo.go index 4fb361de..09cf267d 100644 --- a/gs/dao/player_mongo.go +++ b/gs/dao/player_mongo.go @@ -256,7 +256,7 @@ func (d *Dao) QueryChatMsgListByUid(uid uint32) ([]*model.ChatMsg, error) { context.TODO(), bson.D{{"$or", []bson.D{{{"ToUid", uid}}, {{"Uid", uid}}}}}, options.Find().SetLimit(MaxQueryChatMsgLen), - options.Find().SetSort(bson.M{"Time": -1}), + options.Find().SetSort(bson.M{"Time": 1}), ) if err != nil { return nil, err diff --git a/gs/game/command_controller.go b/gs/game/command_controller.go index 9d071837..b3dc0d40 100644 --- a/gs/game/command_controller.go +++ b/gs/game/command_controller.go @@ -9,6 +9,8 @@ import ( "hk4e/gs/model" ) +// 玩家游戏内GM命令格式解析模块 + // HelpCommand 帮助命令 func (c *CommandManager) HelpCommand(cmd *CommandMessage) { c.SendMessage(cmd.Executor, @@ -158,13 +160,13 @@ func (c *CommandManager) TeleportCommand(cmd *CommandMessage) { c.SendMessage(cmd.Executor, "已将玩家 UID:%v 请求加入目标玩家 UID:%v 的世界。", player.PlayerID, targetUid) } else { // 传送玩家至目标玩家的位置 - c.GMTeleportPlayer(player.PlayerID, target.SceneId, target.Pos.X, target.Pos.Y, target.Pos.Z) + c.gmCmd.GMTeleportPlayer(player.PlayerID, target.SceneId, target.Pos.X, target.Pos.Y, target.Pos.Z) // 发送消息给执行者 c.SendMessage(cmd.Executor, "已将玩家 UID:%v 传送至 目标玩家 UID:%v。", player.PlayerID, targetUid) } } else { // 传送玩家至指定的位置 - c.GMTeleportPlayer(player.PlayerID, sceneId, pos.X, pos.Y, pos.Z) + c.gmCmd.GMTeleportPlayer(player.PlayerID, sceneId, pos.X, pos.Y, pos.Z) // 发送消息给执行者 c.SendMessage(cmd.Executor, "已将玩家 UID:%v 传送至 场景:%v, X:%.2f, Y:%.2f, Z:%.2f。", player.PlayerID, sceneId, pos.X, pos.Y, pos.Z) } @@ -247,7 +249,7 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) { _, ok := GAME_MANAGER.GetAllItemDataConfig()[int32(id)] if ok { // 给予玩家物品 - c.GMAddUserItem(player.PlayerID, id, count) + c.gmCmd.GMAddUserItem(player.PlayerID, id, count) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 物品ID:%v 数量:%v。", player.PlayerID, id, count) return } @@ -255,7 +257,7 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) { _, ok = GAME_MANAGER.GetAllWeaponDataConfig()[int32(id)] if ok { // 给予玩家武器 - c.GMAddUserWeapon(player.PlayerID, id, count) + c.gmCmd.GMAddUserWeapon(player.PlayerID, id, count) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 武器 物品ID:%v 数量:%v。", player.PlayerID, id, count) return @@ -264,7 +266,7 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) { _, ok = GAME_MANAGER.GetAllReliquaryDataConfig()[int32(id)] if ok { // 给予玩家圣遗物 - c.GMAddUserReliquary(player.PlayerID, id, count) + c.gmCmd.GMAddUserReliquary(player.PlayerID, id, count) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 圣遗物 物品ID:%v 数量:%v。", player.PlayerID, id, count) return @@ -273,21 +275,21 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) { _, ok = GAME_MANAGER.GetAllAvatarDataConfig()[int32(id)] if ok { // 给予玩家角色 - c.GMAddUserAvatar(player.PlayerID, id) + c.gmCmd.GMAddUserAvatar(player.PlayerID, id) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 角色ID:%v 数量:%v。", player.PlayerID, id, count) return } // 判断是否为时装 if gdconf.GetAvatarCostumeDataById(int32(id)) != nil { - // 给予玩家角色 - c.GMAddUserCostume(player.PlayerID, id) + // 给予玩家时装 + c.gmCmd.GMAddUserCostume(player.PlayerID, id) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 时装ID:%v 数量:%v。", player.PlayerID, id, count) return } // 判断是否为风之翼 if gdconf.GetAvatarFlycloakDataById(int32(id)) != nil { - // 给予玩家角色 - c.GMAddUserFlycloak(player.PlayerID, id) + // 给予玩家风之翼 + c.gmCmd.GMAddUserFlycloak(player.PlayerID, id) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 风之翼ID:%v 数量:%v。", player.PlayerID, id, count) return } @@ -295,31 +297,31 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) { c.SendMessage(cmd.Executor, "ID:%v 不存在。", id) case "item", "物品": // 给予玩家所有物品 - c.GMAddUserAllItem(player.PlayerID, count) + c.gmCmd.GMAddUserAllItem(player.PlayerID, count) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有物品 数量:%v。", player.PlayerID, count) case "weapon", "武器": // 给予玩家所有武器 - c.GMAddUserAllWeapon(player.PlayerID, count) + c.gmCmd.GMAddUserAllWeapon(player.PlayerID, count) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有武器 数量:%v。", player.PlayerID, count) case "reliquary", "圣遗物": // 给予玩家所有圣遗物 - c.GMAddUserAllReliquary(player.PlayerID, count) + c.gmCmd.GMAddUserAllReliquary(player.PlayerID, count) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有圣遗物 数量:%v。", player.PlayerID, count) case "avatar", "角色": // 给予玩家所有角色 - c.GMAddUserAllAvatar(player.PlayerID) + c.gmCmd.GMAddUserAllAvatar(player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有角色。", player.PlayerID) case "costume", "时装": - // 给予玩家所有角色 - c.GMAddUserAllCostume(player.PlayerID) + // 给予玩家所有时装 + c.gmCmd.GMAddUserAllCostume(player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有时装。", player.PlayerID) case "flycloak", "风之翼": - // 给予玩家所有角色 - c.GMAddUserAllFlycloak(player.PlayerID) + // 给予玩家所有风之翼 + c.gmCmd.GMAddUserAllFlycloak(player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有风之翼。", player.PlayerID) case "all", "全部": // 给予玩家所有内容 - c.GMAddUserAllEvery(player.PlayerID, count, count) // TODO 武器额外获取数量 + c.gmCmd.GMAddUserAllEvery(player.PlayerID, count) // TODO 武器额外获取数量 c.SendMessage(cmd.Executor, "已给予玩家 UID:%v, 所有内容。", player.PlayerID) } } diff --git a/gs/game/command_gm.go b/gs/game/command_gm.go index 6dd04383..a21ad3d3 100644 --- a/gs/game/command_gm.go +++ b/gs/game/command_gm.go @@ -10,8 +10,16 @@ import ( "hk4e/protocol/proto" ) +// GM函数模块 +// GM函数只支持基本类型的简单参数传入 + +type GMCmd struct { +} + +// 玩家通用GM指令 + // GMTeleportPlayer 传送玩家 -func (c *CommandManager) GMTeleportPlayer(userId, sceneId uint32, posX, posY, posZ float64) { +func (g *GMCmd) GMTeleportPlayer(userId, sceneId uint32, posX, posY, posZ float64) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) @@ -25,7 +33,7 @@ func (c *CommandManager) GMTeleportPlayer(userId, sceneId uint32, posX, posY, po } // GMAddUserItem 给予玩家物品 -func (c *CommandManager) GMAddUserItem(userId, itemId, itemCount uint32) { +func (g *GMCmd) GMAddUserItem(userId, itemId, itemCount uint32) { GAME_MANAGER.AddUserItem(userId, []*ChangeItem{ { ItemId: itemId, @@ -35,7 +43,7 @@ func (c *CommandManager) GMAddUserItem(userId, itemId, itemCount uint32) { } // GMAddUserWeapon 给予玩家武器 -func (c *CommandManager) GMAddUserWeapon(userId, itemId, itemCount uint32) { +func (g *GMCmd) GMAddUserWeapon(userId, itemId, itemCount uint32) { // 武器数量 for i := uint32(0); i < itemCount; i++ { // 给予武器 @@ -44,7 +52,7 @@ func (c *CommandManager) GMAddUserWeapon(userId, itemId, itemCount uint32) { } // GMAddUserReliquary 给予玩家圣遗物 -func (c *CommandManager) GMAddUserReliquary(userId, itemId, itemCount uint32) { +func (g *GMCmd) GMAddUserReliquary(userId, itemId, itemCount uint32) { // 圣遗物数量 for i := uint32(0); i < itemCount; i++ { // 给予圣遗物 @@ -53,7 +61,7 @@ func (c *CommandManager) GMAddUserReliquary(userId, itemId, itemCount uint32) { } // GMAddUserAvatar 给予玩家角色 -func (c *CommandManager) GMAddUserAvatar(userId, avatarId uint32) { +func (g *GMCmd) GMAddUserAvatar(userId, avatarId uint32) { // 添加角色 GAME_MANAGER.AddUserAvatar(userId, avatarId) // TODO 设置角色 等以后做到角色升级之类的再说 @@ -61,23 +69,19 @@ func (c *CommandManager) GMAddUserAvatar(userId, avatarId uint32) { } // GMAddUserCostume 给予玩家时装 -func (c *CommandManager) GMAddUserCostume(userId, costumeId uint32) { +func (g *GMCmd) GMAddUserCostume(userId, costumeId uint32) { // 添加时装 GAME_MANAGER.AddUserCostume(userId, costumeId) } // GMAddUserFlycloak 给予玩家风之翼 -func (c *CommandManager) GMAddUserFlycloak(userId, flycloakId uint32) { +func (g *GMCmd) GMAddUserFlycloak(userId, flycloakId uint32) { // 添加风之翼 GAME_MANAGER.AddUserFlycloak(userId, flycloakId) } // GMAddUserAllItem 给予玩家所有物品 -func (c *CommandManager) GMAddUserAllItem(userId, itemCount uint32) { - // 猜猜这样做为啥不行? - // for itemId := range GAME_MANAGER.GetAllItemDataConfig() { - // c.GMAddUserItem(userId, uint32(itemId), itemCount) - // } +func (g *GMCmd) GMAddUserAllItem(userId, itemCount uint32) { itemList := make([]*ChangeItem, 0) for itemId := range GAME_MANAGER.GetAllItemDataConfig() { itemList = append(itemList, &ChangeItem{ @@ -89,57 +93,59 @@ func (c *CommandManager) GMAddUserAllItem(userId, itemCount uint32) { } // GMAddUserAllWeapon 给予玩家所有武器 -func (c *CommandManager) GMAddUserAllWeapon(userId, itemCount uint32) { +func (g *GMCmd) GMAddUserAllWeapon(userId, itemCount uint32) { for itemId := range GAME_MANAGER.GetAllWeaponDataConfig() { - c.GMAddUserWeapon(userId, uint32(itemId), itemCount) + g.GMAddUserWeapon(userId, uint32(itemId), itemCount) } } // GMAddUserAllReliquary 给予玩家所有圣遗物 -func (c *CommandManager) GMAddUserAllReliquary(userId, itemCount uint32) { +func (g *GMCmd) GMAddUserAllReliquary(userId, itemCount uint32) { for itemId := range GAME_MANAGER.GetAllReliquaryDataConfig() { - c.GMAddUserReliquary(userId, uint32(itemId), itemCount) + g.GMAddUserReliquary(userId, uint32(itemId), itemCount) } } // GMAddUserAllAvatar 给予玩家所有角色 -func (c *CommandManager) GMAddUserAllAvatar(userId uint32) { +func (g *GMCmd) GMAddUserAllAvatar(userId uint32) { for avatarId := range GAME_MANAGER.GetAllAvatarDataConfig() { - c.GMAddUserAvatar(userId, uint32(avatarId)) + g.GMAddUserAvatar(userId, uint32(avatarId)) } } // GMAddUserAllCostume 给予玩家所有时装 -func (c *CommandManager) GMAddUserAllCostume(userId uint32) { +func (g *GMCmd) GMAddUserAllCostume(userId uint32) { for costumeId := range gdconf.GetAvatarCostumeDataMap() { - c.GMAddUserCostume(userId, uint32(costumeId)) + g.GMAddUserCostume(userId, uint32(costumeId)) } } // GMAddUserAllFlycloak 给予玩家所有风之翼 -func (c *CommandManager) GMAddUserAllFlycloak(userId uint32) { +func (g *GMCmd) GMAddUserAllFlycloak(userId uint32) { for flycloakId := range gdconf.GetAvatarFlycloakDataMap() { - c.GMAddUserFlycloak(userId, uint32(flycloakId)) + g.GMAddUserFlycloak(userId, uint32(flycloakId)) } } // GMAddUserAllEvery 给予玩家所有内容 -func (c *CommandManager) GMAddUserAllEvery(userId uint32, itemCount uint32, weaponCount uint32) { +func (g *GMCmd) GMAddUserAllEvery(userId, itemCount uint32) { // 给予玩家所有物品 - c.GMAddUserAllItem(userId, itemCount) + g.GMAddUserAllItem(userId, itemCount) // 给予玩家所有武器 - c.GMAddUserAllWeapon(userId, itemCount) + g.GMAddUserAllWeapon(userId, itemCount) // 给予玩家所有圣遗物 - c.GMAddUserAllReliquary(userId, itemCount) + g.GMAddUserAllReliquary(userId, itemCount) // 给予玩家所有角色 - c.GMAddUserAllAvatar(userId) + g.GMAddUserAllAvatar(userId) // 给予玩家所有时装 - c.GMAddUserAllCostume(userId) + g.GMAddUserAllCostume(userId) // 给予玩家所有风之翼 - c.GMAddUserAllFlycloak(userId) + g.GMAddUserAllFlycloak(userId) } -func (c *CommandManager) ChangePlayerCmdPerm(userId uint32, cmdPerm uint8) { +// 系统级GM指令 + +func (g *GMCmd) ChangePlayerCmdPerm(userId uint32, cmdPerm uint8) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) @@ -148,13 +154,13 @@ func (c *CommandManager) ChangePlayerCmdPerm(userId uint32, cmdPerm uint8) { player.CmdPerm = cmdPerm } -func (c *CommandManager) ReloadGameDataConfig() { +func (g *GMCmd) ReloadGameDataConfig() { LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{ EventId: ReloadGameDataConfig, } } -func (c *CommandManager) XLuaDebug(userId uint32, luacBase64 string) { +func (g *GMCmd) XLuaDebug(userId uint32, luacBase64 string) { logger.Debug("xlua debug, uid: %v, luac: %v", userId, luacBase64) player := USER_MANAGER.GetOnlineUser(userId) if player == nil { diff --git a/gs/game/command_manager.go b/gs/game/command_manager.go index 72ee46eb..909441da 100644 --- a/gs/game/command_manager.go +++ b/gs/game/command_manager.go @@ -2,6 +2,7 @@ package game import ( "fmt" + "reflect" "strconv" "strings" @@ -9,7 +10,7 @@ import ( "hk4e/pkg/logger" ) -// 命令管理器 +// GM命令管理器模块 // CommandPerm 命令权限等级 // 0 为普通玩家 数越大权限越大 @@ -42,6 +43,8 @@ type CommandManager struct { commandFuncRouter map[string]CommandFunc // 记录命令处理函数 commandPermMap map[string]CommandPerm // 记录命令对应的权限 commandTextInput chan *CommandMessage // 传输要处理的命令文本 + gmCmd *GMCmd + gmCmdRefValue reflect.Value } // NewCommandManager 新建命令管理器 @@ -50,6 +53,8 @@ func NewCommandManager() *CommandManager { // 初始化 r.commandTextInput = make(chan *CommandMessage, 1000) r.InitRouter() // 初始化路由 + r.gmCmd = new(GMCmd) + r.gmCmdRefValue = reflect.ValueOf(r.gmCmd) return r } @@ -128,21 +133,117 @@ func (c *CommandManager) InputCommand(executor any, text string) { c.commandTextInput <- &CommandMessage{Executor: executor, Text: text} } +func (c *CommandManager) CallGMCmd(funcName string, paramList []string) bool { + fn := c.gmCmdRefValue.MethodByName(funcName) + if !fn.IsValid() { + return false + } + if fn.Type().NumIn() != len(paramList) { + return false + } + in := make([]reflect.Value, fn.Type().NumIn()) + for i := 0; i < fn.Type().NumIn(); i++ { + kind := fn.Type().In(i).Kind() + param := paramList[i] + var value reflect.Value + switch kind { + case reflect.Int: + val, err := strconv.ParseInt(param, 10, 64) + if err != nil { + return false + } + value = reflect.ValueOf(int(val)) + case reflect.Uint: + val, err := strconv.ParseUint(param, 10, 64) + if err != nil { + return false + } + value = reflect.ValueOf(uint(val)) + case reflect.Int8: + val, err := strconv.ParseInt(param, 10, 8) + if err != nil { + return false + } + value = reflect.ValueOf(int8(val)) + case reflect.Uint8: + val, err := strconv.ParseUint(param, 10, 8) + if err != nil { + return false + } + value = reflect.ValueOf(uint8(val)) + case reflect.Int16: + val, err := strconv.ParseInt(param, 10, 16) + if err != nil { + return false + } + value = reflect.ValueOf(int16(val)) + case reflect.Uint16: + val, err := strconv.ParseUint(param, 10, 16) + if err != nil { + return false + } + value = reflect.ValueOf(uint16(val)) + case reflect.Int32: + val, err := strconv.ParseInt(param, 10, 32) + if err != nil { + return false + } + value = reflect.ValueOf(int32(val)) + case reflect.Uint32: + val, err := strconv.ParseUint(param, 10, 32) + if err != nil { + return false + } + value = reflect.ValueOf(uint32(val)) + case reflect.Int64: + val, err := strconv.ParseInt(param, 10, 64) + if err != nil { + return false + } + value = reflect.ValueOf(val) + case reflect.Uint64: + val, err := strconv.ParseUint(param, 10, 64) + if err != nil { + return false + } + value = reflect.ValueOf(val) + case reflect.Float32: + val, err := strconv.ParseFloat(param, 32) + if err != nil { + return false + } + value = reflect.ValueOf(float32(val)) + case reflect.Float64: + val, err := strconv.ParseFloat(param, 64) + if err != nil { + return false + } + value = reflect.ValueOf(val) + case reflect.Bool: + val, err := strconv.ParseBool(param) + if err != nil { + return false + } + value = reflect.ValueOf(val) + case reflect.String: + value = reflect.ValueOf(param) + default: + return false + } + in[i] = value + } + fn.Call(in) + return true +} + // HandleCommand 处理命令 // 主协程接收到命令消息后执行 func (c *CommandManager) HandleCommand(cmd *CommandMessage) { + // 直接执行GM函数 if cmd.FuncName != "" { logger.Info("run gm cmd, FuncName: %v, Param: %v", cmd.FuncName, cmd.Param) - // TODO 反射调用command_gm.go中的函数并反射解析传入参数类型 - if cmd.FuncName == "ReloadGameDataConfig" && len(cmd.Param) == 0 { - c.ReloadGameDataConfig() - } else if cmd.FuncName == "XLuaDebug" && len(cmd.Param) == 2 { - uid, err := strconv.Atoi(cmd.Param[0]) - if err != nil { - return - } - c.XLuaDebug(uint32(uid), cmd.Param[1]) - } + // 反射调用command_gm.go中的函数并反射解析传入参数类型 + c.CallGMCmd(cmd.FuncName, cmd.Param) return } diff --git a/gs/game/player_fight_sync.go b/gs/game/player_fight_sync.go index 42679442..a37e73d0 100644 --- a/gs/game/player_fight_sync.go +++ b/gs/game/player_fight_sync.go @@ -15,8 +15,6 @@ import ( pb "google.golang.org/protobuf/proto" ) -// TODO 暂时只做3.2协议的兼容了 在GS这边处理不同版本的协议太烦人了 有机会全部改到GATE那边处理 GS所有接收和发送的都应该是3.2版本的协议 - var cmdProtoMap *cmd.CmdProtoMap = nil func DoForward[IET model.InvokeEntryType](player *model.Player, invokeHandler *model.InvokeHandler[IET], diff --git a/gs/game/player_reliquary.go b/gs/game/player_reliquary.go index 7f121828..478a4631 100644 --- a/gs/game/player_reliquary.go +++ b/gs/game/player_reliquary.go @@ -65,6 +65,10 @@ func (g *GameManager) AddUserReliquary(userId uint32, itemId uint32) uint64 { mainPropId := uint32(reliquaryMainConfig.MainPropId) // 玩家添加圣遗物 dbReliquary := player.GetDbReliquary() + // 校验背包圣遗物容量 + if dbReliquary.GetReliquaryMapLen() > constant.STORE_PACK_LIMIT_RELIQUARY { + return 0 + } dbReliquary.AddReliquary(player, itemId, reliquaryId, mainPropId) reliquary := dbReliquary.GetReliquary(reliquaryId) if reliquary == nil { diff --git a/gs/game/player_weapon.go b/gs/game/player_weapon.go index 63b72631..a11898b2 100644 --- a/gs/game/player_weapon.go +++ b/gs/game/player_weapon.go @@ -33,6 +33,10 @@ func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 { } weaponId := uint64(g.snowflake.GenId()) dbWeapon := player.GetDbWeapon() + // 校验背包武器容量 + if dbWeapon.GetWeaponMapLen() > constant.STORE_PACK_LIMIT_WEAPON { + return 0 + } dbWeapon.AddWeapon(player, itemId, weaponId) weapon := dbWeapon.GetWeapon(weaponId) if weapon == nil { diff --git a/gs/model/db_reliquary.go b/gs/model/db_reliquary.go index 9e4a01ca..380b0a94 100644 --- a/gs/model/db_reliquary.go +++ b/gs/model/db_reliquary.go @@ -1,7 +1,6 @@ package model import ( - "hk4e/common/constant" "hk4e/gdconf" "hk4e/pkg/logger" ) @@ -32,6 +31,10 @@ type Reliquary struct { Guid uint64 `bson:"-" msgpack:"-"` } +func (r *DbReliquary) GetReliquaryMapLen() int { + return len(r.ReliquaryMap) +} + func (r *DbReliquary) InitAllReliquary(player *Player) { for _, reliquary := range r.ReliquaryMap { r.InitReliquary(player, reliquary) @@ -69,10 +72,6 @@ func (r *DbReliquary) GetReliquary(reliquaryId uint64) *Reliquary { } func (r *DbReliquary) AddReliquary(player *Player, itemId uint32, reliquaryId uint64, mainPropId uint32) { - // 校验背包圣遗物容量 - if len(r.ReliquaryMap) > constant.STORE_PACK_LIMIT_RELIQUARY { - return - } itemDataConfig := gdconf.GetItemDataById(int32(itemId)) if itemDataConfig == nil { logger.Error("reliquary config is nil, itemId: %v", itemId) diff --git a/gs/model/db_weapon.go b/gs/model/db_weapon.go index d97b5b85..96216512 100644 --- a/gs/model/db_weapon.go +++ b/gs/model/db_weapon.go @@ -1,7 +1,6 @@ package model import ( - "hk4e/common/constant" "hk4e/gdconf" "hk4e/pkg/logger" ) @@ -32,6 +31,10 @@ type Weapon struct { Guid uint64 `bson:"-" msgpack:"-"` } +func (w *DbWeapon) GetWeaponMapLen() int { + return len(w.WeaponMap) +} + func (w *DbWeapon) InitAllWeapon(player *Player) { for _, weapon := range w.WeaponMap { w.InitWeapon(player, weapon) @@ -63,10 +66,6 @@ func (w *DbWeapon) GetWeapon(weaponId uint64) *Weapon { } func (w *DbWeapon) AddWeapon(player *Player, itemId uint32, weaponId uint64) { - // 校验背包武器容量 - if len(w.WeaponMap) > constant.STORE_PACK_LIMIT_WEAPON { - return - } itemDataConfig := gdconf.GetItemDataById(int32(itemId)) if itemDataConfig == nil { logger.Error("weapon config is nil, itemId: %v", itemId)