网关客户端协议代理功能加入二级pb数据解析

This commit is contained in:
flswld
2023-03-14 18:30:07 +08:00
parent 2c35fc0df4
commit cd922d1a38
11 changed files with 331 additions and 77 deletions

View File

@@ -64,6 +64,7 @@ func ProtoDecode(kcpMsg *KcpMsg,
if len(delList) != 0 { if len(delList) != 0 {
logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName) logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName)
} }
ConvClientPbDataToServer(serverProtoObj, clientCmdProtoMap)
serverProtoData, err := pb.Marshal(serverProtoObj) serverProtoData, err := pb.Marshal(serverProtoObj)
if err != nil { if err != nil {
logger.Error("marshal server proto error: %v", err) logger.Error("marshal server proto error: %v", err)
@@ -175,6 +176,7 @@ func ProtoDecodePayloadLoop(cmdId uint16, protoData []byte, protoMessageList *[]
if len(delList) != 0 { if len(delList) != 0 {
logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName) logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName)
} }
ConvClientPbDataToServer(serverProtoObj, clientCmdProtoMap)
serverProtoData, err := pb.Marshal(serverProtoObj) serverProtoData, err := pb.Marshal(serverProtoObj)
if err != nil { if err != nil {
logger.Error("marshal server proto error: %v", err) logger.Error("marshal server proto error: %v", err)
@@ -257,6 +259,7 @@ func ProtoEncode(protoMsg *ProtoMsg,
if len(delList) != 0 { if len(delList) != 0 {
logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName) logger.Error("delete field name list: %v, cmdName: %v", delList, cmdName)
} }
ConvServerPbDataToClient(clientProtoObj, clientCmdProtoMap)
clientProtoData, err := pb.Marshal(clientProtoObj) clientProtoData, err := pb.Marshal(clientProtoObj)
if err != nil { if err != nil {
logger.Error("marshal client proto error: %v", err) logger.Error("marshal client proto error: %v", err)
@@ -297,8 +300,14 @@ func EncodeProtoToPayload(protoObj pb.Message, serverCmdProtoMap *cmd.CmdProtoMa
return protoData return protoData
} }
// 网关客户端协议代理相关反射方法
func GetClientProtoObjByName(protoObjName string, clientCmdProtoMap *client_proto.ClientCmdProtoMap) pb.Message { func GetClientProtoObjByName(protoObjName string, clientCmdProtoMap *client_proto.ClientCmdProtoMap) pb.Message {
fn := clientCmdProtoMap.RefValue.MethodByName("GetClientProtoObjByName") fn := clientCmdProtoMap.RefValue.MethodByName("GetClientProtoObjByName")
if !fn.IsValid() {
logger.Error("fn is nil")
return nil
}
ret := fn.Call([]reflect.Value{reflect.ValueOf(protoObjName)}) ret := fn.Call([]reflect.Value{reflect.ValueOf(protoObjName)})
obj := ret[0].Interface() obj := ret[0].Interface()
if obj == nil { if obj == nil {
@@ -308,3 +317,135 @@ func GetClientProtoObjByName(protoObjName string, clientCmdProtoMap *client_prot
clientProtoObj := obj.(pb.Message) clientProtoObj := obj.(pb.Message)
return clientProtoObj 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
}

View File

@@ -11,9 +11,9 @@ import (
"github.com/jszwec/csvutil" "github.com/jszwec/csvutil"
) )
// ItemData 统一道具配置表 // ItemData 道具分类分表整合配置表
type ItemData struct { type ItemData struct {
// 公共字段 // 公共表头字段
ItemId int32 `csv:"ItemId"` // ID ItemId int32 `csv:"ItemId"` // ID
Type int32 `csv:"Type,omitempty"` // 类型 Type int32 `csv:"Type,omitempty"` // 类型
Weight int32 `csv:"Weight,omitempty"` // 重量 Weight int32 `csv:"Weight,omitempty"` // 重量

View File

@@ -256,7 +256,7 @@ func (d *Dao) QueryChatMsgListByUid(uid uint32) ([]*model.ChatMsg, error) {
context.TODO(), context.TODO(),
bson.D{{"$or", []bson.D{{{"ToUid", uid}}, {{"Uid", uid}}}}}, bson.D{{"$or", []bson.D{{{"ToUid", uid}}, {{"Uid", uid}}}}},
options.Find().SetLimit(MaxQueryChatMsgLen), options.Find().SetLimit(MaxQueryChatMsgLen),
options.Find().SetSort(bson.M{"Time": -1}), options.Find().SetSort(bson.M{"Time": 1}),
) )
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -9,6 +9,8 @@ import (
"hk4e/gs/model" "hk4e/gs/model"
) )
// 玩家游戏内GM命令格式解析模块
// HelpCommand 帮助命令 // HelpCommand 帮助命令
func (c *CommandManager) HelpCommand(cmd *CommandMessage) { func (c *CommandManager) HelpCommand(cmd *CommandMessage) {
c.SendMessage(cmd.Executor, 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) c.SendMessage(cmd.Executor, "已将玩家 UID%v 请求加入目标玩家 UID%v 的世界。", player.PlayerID, targetUid)
} else { } 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) c.SendMessage(cmd.Executor, "已将玩家 UID%v 传送至 目标玩家 UID%v。", player.PlayerID, targetUid)
} }
} else { } 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) 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)] _, ok := GAME_MANAGER.GetAllItemDataConfig()[int32(id)]
if ok { 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) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 物品ID%v 数量:%v。", player.PlayerID, id, count)
return return
} }
@@ -255,7 +257,7 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) {
_, ok = GAME_MANAGER.GetAllWeaponDataConfig()[int32(id)] _, ok = GAME_MANAGER.GetAllWeaponDataConfig()[int32(id)]
if ok { 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) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 武器 物品ID%v 数量:%v。", player.PlayerID, id, count)
return return
@@ -264,7 +266,7 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) {
_, ok = GAME_MANAGER.GetAllReliquaryDataConfig()[int32(id)] _, ok = GAME_MANAGER.GetAllReliquaryDataConfig()[int32(id)]
if ok { 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) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 圣遗物 物品ID%v 数量:%v。", player.PlayerID, id, count)
return return
@@ -273,21 +275,21 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) {
_, ok = GAME_MANAGER.GetAllAvatarDataConfig()[int32(id)] _, ok = GAME_MANAGER.GetAllAvatarDataConfig()[int32(id)]
if ok { 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) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 角色ID%v 数量:%v。", player.PlayerID, id, count)
return return
} }
// 判断是否为时装 // 判断是否为时装
if gdconf.GetAvatarCostumeDataById(int32(id)) != nil { 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) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 时装ID%v 数量:%v。", player.PlayerID, id, count)
return return
} }
// 判断是否为风之翼 // 判断是否为风之翼
if gdconf.GetAvatarFlycloakDataById(int32(id)) != nil { 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) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 风之翼ID%v 数量:%v。", player.PlayerID, id, count)
return return
} }
@@ -295,31 +297,31 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) {
c.SendMessage(cmd.Executor, "ID%v 不存在。", id) c.SendMessage(cmd.Executor, "ID%v 不存在。", id)
case "item", "物品": case "item", "物品":
// 给予玩家所有物品 // 给予玩家所有物品
c.GMAddUserAllItem(player.PlayerID, count) c.gmCmd.GMAddUserAllItem(player.PlayerID, count)
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有物品 数量:%v。", player.PlayerID, count) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有物品 数量:%v。", player.PlayerID, count)
case "weapon", "武器": case "weapon", "武器":
// 给予玩家所有武器 // 给予玩家所有武器
c.GMAddUserAllWeapon(player.PlayerID, count) c.gmCmd.GMAddUserAllWeapon(player.PlayerID, count)
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有武器 数量:%v。", player.PlayerID, count) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有武器 数量:%v。", player.PlayerID, count)
case "reliquary", "圣遗物": case "reliquary", "圣遗物":
// 给予玩家所有圣遗物 // 给予玩家所有圣遗物
c.GMAddUserAllReliquary(player.PlayerID, count) c.gmCmd.GMAddUserAllReliquary(player.PlayerID, count)
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有圣遗物 数量:%v。", player.PlayerID, count) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有圣遗物 数量:%v。", player.PlayerID, count)
case "avatar", "角色": case "avatar", "角色":
// 给予玩家所有角色 // 给予玩家所有角色
c.GMAddUserAllAvatar(player.PlayerID) c.gmCmd.GMAddUserAllAvatar(player.PlayerID)
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有角色。", player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有角色。", player.PlayerID)
case "costume", "时装": case "costume", "时装":
// 给予玩家所有角色 // 给予玩家所有时装
c.GMAddUserAllCostume(player.PlayerID) c.gmCmd.GMAddUserAllCostume(player.PlayerID)
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有时装。", player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有时装。", player.PlayerID)
case "flycloak", "风之翼": case "flycloak", "风之翼":
// 给予玩家所有角色 // 给予玩家所有风之翼
c.GMAddUserAllFlycloak(player.PlayerID) c.gmCmd.GMAddUserAllFlycloak(player.PlayerID)
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有风之翼。", player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有风之翼。", player.PlayerID)
case "all", "全部": case "all", "全部":
// 给予玩家所有内容 // 给予玩家所有内容
c.GMAddUserAllEvery(player.PlayerID, count, count) // TODO 武器额外获取数量 c.gmCmd.GMAddUserAllEvery(player.PlayerID, count) // TODO 武器额外获取数量
c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有内容。", player.PlayerID) c.SendMessage(cmd.Executor, "已给予玩家 UID%v, 所有内容。", player.PlayerID)
} }
} }

View File

@@ -10,8 +10,16 @@ import (
"hk4e/protocol/proto" "hk4e/protocol/proto"
) )
// GM函数模块
// GM函数只支持基本类型的简单参数传入
type GMCmd struct {
}
// 玩家通用GM指令
// GMTeleportPlayer 传送玩家 // 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) player := USER_MANAGER.GetOnlineUser(userId)
if player == nil { if player == nil {
logger.Error("player is nil, uid: %v", userId) logger.Error("player is nil, uid: %v", userId)
@@ -25,7 +33,7 @@ func (c *CommandManager) GMTeleportPlayer(userId, sceneId uint32, posX, posY, po
} }
// GMAddUserItem 给予玩家物品 // GMAddUserItem 给予玩家物品
func (c *CommandManager) GMAddUserItem(userId, itemId, itemCount uint32) { func (g *GMCmd) GMAddUserItem(userId, itemId, itemCount uint32) {
GAME_MANAGER.AddUserItem(userId, []*ChangeItem{ GAME_MANAGER.AddUserItem(userId, []*ChangeItem{
{ {
ItemId: itemId, ItemId: itemId,
@@ -35,7 +43,7 @@ func (c *CommandManager) GMAddUserItem(userId, itemId, itemCount uint32) {
} }
// GMAddUserWeapon 给予玩家武器 // GMAddUserWeapon 给予玩家武器
func (c *CommandManager) GMAddUserWeapon(userId, itemId, itemCount uint32) { func (g *GMCmd) GMAddUserWeapon(userId, itemId, itemCount uint32) {
// 武器数量 // 武器数量
for i := uint32(0); i < itemCount; i++ { for i := uint32(0); i < itemCount; i++ {
// 给予武器 // 给予武器
@@ -44,7 +52,7 @@ func (c *CommandManager) GMAddUserWeapon(userId, itemId, itemCount uint32) {
} }
// GMAddUserReliquary 给予玩家圣遗物 // GMAddUserReliquary 给予玩家圣遗物
func (c *CommandManager) GMAddUserReliquary(userId, itemId, itemCount uint32) { func (g *GMCmd) GMAddUserReliquary(userId, itemId, itemCount uint32) {
// 圣遗物数量 // 圣遗物数量
for i := uint32(0); i < itemCount; i++ { for i := uint32(0); i < itemCount; i++ {
// 给予圣遗物 // 给予圣遗物
@@ -53,7 +61,7 @@ func (c *CommandManager) GMAddUserReliquary(userId, itemId, itemCount uint32) {
} }
// GMAddUserAvatar 给予玩家角色 // GMAddUserAvatar 给予玩家角色
func (c *CommandManager) GMAddUserAvatar(userId, avatarId uint32) { func (g *GMCmd) GMAddUserAvatar(userId, avatarId uint32) {
// 添加角色 // 添加角色
GAME_MANAGER.AddUserAvatar(userId, avatarId) GAME_MANAGER.AddUserAvatar(userId, avatarId)
// TODO 设置角色 等以后做到角色升级之类的再说 // TODO 设置角色 等以后做到角色升级之类的再说
@@ -61,23 +69,19 @@ func (c *CommandManager) GMAddUserAvatar(userId, avatarId uint32) {
} }
// GMAddUserCostume 给予玩家时装 // GMAddUserCostume 给予玩家时装
func (c *CommandManager) GMAddUserCostume(userId, costumeId uint32) { func (g *GMCmd) GMAddUserCostume(userId, costumeId uint32) {
// 添加时装 // 添加时装
GAME_MANAGER.AddUserCostume(userId, costumeId) GAME_MANAGER.AddUserCostume(userId, costumeId)
} }
// GMAddUserFlycloak 给予玩家风之翼 // GMAddUserFlycloak 给予玩家风之翼
func (c *CommandManager) GMAddUserFlycloak(userId, flycloakId uint32) { func (g *GMCmd) GMAddUserFlycloak(userId, flycloakId uint32) {
// 添加风之翼 // 添加风之翼
GAME_MANAGER.AddUserFlycloak(userId, flycloakId) GAME_MANAGER.AddUserFlycloak(userId, flycloakId)
} }
// GMAddUserAllItem 给予玩家所有物品 // GMAddUserAllItem 给予玩家所有物品
func (c *CommandManager) GMAddUserAllItem(userId, itemCount uint32) { func (g *GMCmd) GMAddUserAllItem(userId, itemCount uint32) {
// 猜猜这样做为啥不行?
// for itemId := range GAME_MANAGER.GetAllItemDataConfig() {
// c.GMAddUserItem(userId, uint32(itemId), itemCount)
// }
itemList := make([]*ChangeItem, 0) itemList := make([]*ChangeItem, 0)
for itemId := range GAME_MANAGER.GetAllItemDataConfig() { for itemId := range GAME_MANAGER.GetAllItemDataConfig() {
itemList = append(itemList, &ChangeItem{ itemList = append(itemList, &ChangeItem{
@@ -89,57 +93,59 @@ func (c *CommandManager) GMAddUserAllItem(userId, itemCount uint32) {
} }
// GMAddUserAllWeapon 给予玩家所有武器 // GMAddUserAllWeapon 给予玩家所有武器
func (c *CommandManager) GMAddUserAllWeapon(userId, itemCount uint32) { func (g *GMCmd) GMAddUserAllWeapon(userId, itemCount uint32) {
for itemId := range GAME_MANAGER.GetAllWeaponDataConfig() { for itemId := range GAME_MANAGER.GetAllWeaponDataConfig() {
c.GMAddUserWeapon(userId, uint32(itemId), itemCount) g.GMAddUserWeapon(userId, uint32(itemId), itemCount)
} }
} }
// GMAddUserAllReliquary 给予玩家所有圣遗物 // GMAddUserAllReliquary 给予玩家所有圣遗物
func (c *CommandManager) GMAddUserAllReliquary(userId, itemCount uint32) { func (g *GMCmd) GMAddUserAllReliquary(userId, itemCount uint32) {
for itemId := range GAME_MANAGER.GetAllReliquaryDataConfig() { for itemId := range GAME_MANAGER.GetAllReliquaryDataConfig() {
c.GMAddUserReliquary(userId, uint32(itemId), itemCount) g.GMAddUserReliquary(userId, uint32(itemId), itemCount)
} }
} }
// GMAddUserAllAvatar 给予玩家所有角色 // GMAddUserAllAvatar 给予玩家所有角色
func (c *CommandManager) GMAddUserAllAvatar(userId uint32) { func (g *GMCmd) GMAddUserAllAvatar(userId uint32) {
for avatarId := range GAME_MANAGER.GetAllAvatarDataConfig() { for avatarId := range GAME_MANAGER.GetAllAvatarDataConfig() {
c.GMAddUserAvatar(userId, uint32(avatarId)) g.GMAddUserAvatar(userId, uint32(avatarId))
} }
} }
// GMAddUserAllCostume 给予玩家所有时装 // GMAddUserAllCostume 给予玩家所有时装
func (c *CommandManager) GMAddUserAllCostume(userId uint32) { func (g *GMCmd) GMAddUserAllCostume(userId uint32) {
for costumeId := range gdconf.GetAvatarCostumeDataMap() { for costumeId := range gdconf.GetAvatarCostumeDataMap() {
c.GMAddUserCostume(userId, uint32(costumeId)) g.GMAddUserCostume(userId, uint32(costumeId))
} }
} }
// GMAddUserAllFlycloak 给予玩家所有风之翼 // GMAddUserAllFlycloak 给予玩家所有风之翼
func (c *CommandManager) GMAddUserAllFlycloak(userId uint32) { func (g *GMCmd) GMAddUserAllFlycloak(userId uint32) {
for flycloakId := range gdconf.GetAvatarFlycloakDataMap() { for flycloakId := range gdconf.GetAvatarFlycloakDataMap() {
c.GMAddUserFlycloak(userId, uint32(flycloakId)) g.GMAddUserFlycloak(userId, uint32(flycloakId))
} }
} }
// GMAddUserAllEvery 给予玩家所有内容 // 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) player := USER_MANAGER.GetOnlineUser(userId)
if player == nil { if player == nil {
logger.Error("player is nil, uid: %v", userId) logger.Error("player is nil, uid: %v", userId)
@@ -148,13 +154,13 @@ func (c *CommandManager) ChangePlayerCmdPerm(userId uint32, cmdPerm uint8) {
player.CmdPerm = cmdPerm player.CmdPerm = cmdPerm
} }
func (c *CommandManager) ReloadGameDataConfig() { func (g *GMCmd) ReloadGameDataConfig() {
LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{ LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{
EventId: ReloadGameDataConfig, 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) logger.Debug("xlua debug, uid: %v, luac: %v", userId, luacBase64)
player := USER_MANAGER.GetOnlineUser(userId) player := USER_MANAGER.GetOnlineUser(userId)
if player == nil { if player == nil {

View File

@@ -2,6 +2,7 @@ package game
import ( import (
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
@@ -9,7 +10,7 @@ import (
"hk4e/pkg/logger" "hk4e/pkg/logger"
) )
// 命令管理器 // GM命令管理器模块
// CommandPerm 命令权限等级 // CommandPerm 命令权限等级
// 0 为普通玩家 数越大权限越大 // 0 为普通玩家 数越大权限越大
@@ -42,6 +43,8 @@ type CommandManager struct {
commandFuncRouter map[string]CommandFunc // 记录命令处理函数 commandFuncRouter map[string]CommandFunc // 记录命令处理函数
commandPermMap map[string]CommandPerm // 记录命令对应的权限 commandPermMap map[string]CommandPerm // 记录命令对应的权限
commandTextInput chan *CommandMessage // 传输要处理的命令文本 commandTextInput chan *CommandMessage // 传输要处理的命令文本
gmCmd *GMCmd
gmCmdRefValue reflect.Value
} }
// NewCommandManager 新建命令管理器 // NewCommandManager 新建命令管理器
@@ -50,6 +53,8 @@ func NewCommandManager() *CommandManager {
// 初始化 // 初始化
r.commandTextInput = make(chan *CommandMessage, 1000) r.commandTextInput = make(chan *CommandMessage, 1000)
r.InitRouter() // 初始化路由 r.InitRouter() // 初始化路由
r.gmCmd = new(GMCmd)
r.gmCmdRefValue = reflect.ValueOf(r.gmCmd)
return r return r
} }
@@ -128,21 +133,117 @@ func (c *CommandManager) InputCommand(executor any, text string) {
c.commandTextInput <- &CommandMessage{Executor: executor, Text: text} 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 处理命令 // HandleCommand 处理命令
// 主协程接收到命令消息后执行 // 主协程接收到命令消息后执行
func (c *CommandManager) HandleCommand(cmd *CommandMessage) { func (c *CommandManager) HandleCommand(cmd *CommandMessage) {
// 直接执行GM函数
if cmd.FuncName != "" { if cmd.FuncName != "" {
logger.Info("run gm cmd, FuncName: %v, Param: %v", cmd.FuncName, cmd.Param) logger.Info("run gm cmd, FuncName: %v, Param: %v", cmd.FuncName, cmd.Param)
// TODO 反射调用command_gm.go中的函数并反射解析传入参数类型 // 反射调用command_gm.go中的函数并反射解析传入参数类型
if cmd.FuncName == "ReloadGameDataConfig" && len(cmd.Param) == 0 { c.CallGMCmd(cmd.FuncName, cmd.Param)
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])
}
return return
} }

View File

@@ -15,8 +15,6 @@ import (
pb "google.golang.org/protobuf/proto" pb "google.golang.org/protobuf/proto"
) )
// TODO 暂时只做3.2协议的兼容了 在GS这边处理不同版本的协议太烦人了 有机会全部改到GATE那边处理 GS所有接收和发送的都应该是3.2版本的协议
var cmdProtoMap *cmd.CmdProtoMap = nil var cmdProtoMap *cmd.CmdProtoMap = nil
func DoForward[IET model.InvokeEntryType](player *model.Player, invokeHandler *model.InvokeHandler[IET], func DoForward[IET model.InvokeEntryType](player *model.Player, invokeHandler *model.InvokeHandler[IET],

View File

@@ -65,6 +65,10 @@ func (g *GameManager) AddUserReliquary(userId uint32, itemId uint32) uint64 {
mainPropId := uint32(reliquaryMainConfig.MainPropId) mainPropId := uint32(reliquaryMainConfig.MainPropId)
// 玩家添加圣遗物 // 玩家添加圣遗物
dbReliquary := player.GetDbReliquary() dbReliquary := player.GetDbReliquary()
// 校验背包圣遗物容量
if dbReliquary.GetReliquaryMapLen() > constant.STORE_PACK_LIMIT_RELIQUARY {
return 0
}
dbReliquary.AddReliquary(player, itemId, reliquaryId, mainPropId) dbReliquary.AddReliquary(player, itemId, reliquaryId, mainPropId)
reliquary := dbReliquary.GetReliquary(reliquaryId) reliquary := dbReliquary.GetReliquary(reliquaryId)
if reliquary == nil { if reliquary == nil {

View File

@@ -33,6 +33,10 @@ func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 {
} }
weaponId := uint64(g.snowflake.GenId()) weaponId := uint64(g.snowflake.GenId())
dbWeapon := player.GetDbWeapon() dbWeapon := player.GetDbWeapon()
// 校验背包武器容量
if dbWeapon.GetWeaponMapLen() > constant.STORE_PACK_LIMIT_WEAPON {
return 0
}
dbWeapon.AddWeapon(player, itemId, weaponId) dbWeapon.AddWeapon(player, itemId, weaponId)
weapon := dbWeapon.GetWeapon(weaponId) weapon := dbWeapon.GetWeapon(weaponId)
if weapon == nil { if weapon == nil {

View File

@@ -1,7 +1,6 @@
package model package model
import ( import (
"hk4e/common/constant"
"hk4e/gdconf" "hk4e/gdconf"
"hk4e/pkg/logger" "hk4e/pkg/logger"
) )
@@ -32,6 +31,10 @@ type Reliquary struct {
Guid uint64 `bson:"-" msgpack:"-"` Guid uint64 `bson:"-" msgpack:"-"`
} }
func (r *DbReliquary) GetReliquaryMapLen() int {
return len(r.ReliquaryMap)
}
func (r *DbReliquary) InitAllReliquary(player *Player) { func (r *DbReliquary) InitAllReliquary(player *Player) {
for _, reliquary := range r.ReliquaryMap { for _, reliquary := range r.ReliquaryMap {
r.InitReliquary(player, reliquary) 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) { 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)) itemDataConfig := gdconf.GetItemDataById(int32(itemId))
if itemDataConfig == nil { if itemDataConfig == nil {
logger.Error("reliquary config is nil, itemId: %v", itemId) logger.Error("reliquary config is nil, itemId: %v", itemId)

View File

@@ -1,7 +1,6 @@
package model package model
import ( import (
"hk4e/common/constant"
"hk4e/gdconf" "hk4e/gdconf"
"hk4e/pkg/logger" "hk4e/pkg/logger"
) )
@@ -32,6 +31,10 @@ type Weapon struct {
Guid uint64 `bson:"-" msgpack:"-"` Guid uint64 `bson:"-" msgpack:"-"`
} }
func (w *DbWeapon) GetWeaponMapLen() int {
return len(w.WeaponMap)
}
func (w *DbWeapon) InitAllWeapon(player *Player) { func (w *DbWeapon) InitAllWeapon(player *Player) {
for _, weapon := range w.WeaponMap { for _, weapon := range w.WeaponMap {
w.InitWeapon(player, weapon) 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) { 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)) itemDataConfig := gdconf.GetItemDataById(int32(itemId))
if itemDataConfig == nil { if itemDataConfig == nil {
logger.Error("weapon config is nil, itemId: %v", itemId) logger.Error("weapon config is nil, itemId: %v", itemId)