From 7d21f24dc8537b2728c6a43be1226235a606c2b9 Mon Sep 17 00:00:00 2001 From: flswld Date: Tue, 21 Feb 2023 19:01:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=8E=A5=E5=8F=96=E3=80=81?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E3=80=81=E5=AE=8C=E6=88=90=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/constant/quest_type.go | 15 ++ gdconf/game_data_config.go | 2 + gdconf/item_data.go | 2 +- gdconf/quest_data.go | 136 ++++++++++++++-- gdconf/table_struct_mapping.json | 270 +++++++++++++++++++++++++++++++ gdconf/trigger_data.go | 40 +++++ gs/game/player_login.go | 42 +---- gs/game/player_quest.go | 157 ++++++++++++++++++ gs/game/route_manager.go | 1 + gs/model/db_quest.go | 132 +++++++++++++++ gs/model/player.go | 1 + 11 files changed, 746 insertions(+), 52 deletions(-) create mode 100644 common/constant/quest_type.go create mode 100644 gdconf/trigger_data.go create mode 100644 gs/game/player_quest.go create mode 100644 gs/model/db_quest.go diff --git a/common/constant/quest_type.go b/common/constant/quest_type.go new file mode 100644 index 00000000..a08c24b2 --- /dev/null +++ b/common/constant/quest_type.go @@ -0,0 +1,15 @@ +package constant + +const ( + QUEST_STATE_TYPE_ACCEPT uint32 = 1 + QUEST_STATE_TYPE_EXEC uint32 = 2 + QUEST_STATE_TYPE_FINISH uint32 = 3 +) + +const ( + QUEST_ACCEPT_COND_TYPE_QUEST_STATE_EQ int32 = 1 +) + +const ( + QUEST_FINISH_COND_TYPE_SCENE_TRIGGER = 6 +) diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index 9b9a2934..1248626f 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -51,6 +51,7 @@ type GameDataConfig struct { ReliquaryMainDataMap map[int32]map[int32]*ReliquaryMainData // 圣遗物主属性 ReliquaryAffixDataMap map[int32]map[int32]*ReliquaryAffixData // 圣遗物追加属性 QuestDataMap map[int32]*QuestData // 任务 + TriggerDataMap map[int32]*TriggerData // 场景LUA触发器 } func InitGameDataConfig() { @@ -137,6 +138,7 @@ func (g *GameDataConfig) load() { g.loadReliquaryMainData() // 圣遗物主属性 g.loadReliquaryAffixData() // 圣遗物追加属性 g.loadQuestData() // 任务 + g.loadTriggerData() // 场景LUA触发器 } func (g *GameDataConfig) readCsvFileData(fileName string) []byte { diff --git a/gdconf/item_data.go b/gdconf/item_data.go index fd8c1ae9..a1079e0e 100644 --- a/gdconf/item_data.go +++ b/gdconf/item_data.go @@ -2,10 +2,10 @@ package gdconf import ( "fmt" - "hk4e/common/constant" "strconv" "strings" + "hk4e/common/constant" "hk4e/pkg/logger" "github.com/jszwec/csvutil" diff --git a/gdconf/quest_data.go b/gdconf/quest_data.go index bd23d78d..a2906565 100644 --- a/gdconf/quest_data.go +++ b/gdconf/quest_data.go @@ -8,6 +8,13 @@ import ( "github.com/jszwec/csvutil" ) +type QuestCond struct { + Type int32 + Param []int32 + ComplexParam string + Count int32 +} + // QuestData 任务配置表 type QuestData struct { QuestId int32 `csv:"QuestId"` // ID @@ -61,26 +68,131 @@ type QuestData struct { FailCondType3Param2 int32 `csv:"FailCondType3Param2,omitempty"` // [失败条件]3参数2 FailCondType3ComplexParam string `csv:"FailCondType3ComplexParam,omitempty"` // [失败条件]3复杂参数 FailCondType3Count int32 `csv:"FailCondType3Count,omitempty"` // [失败条件]3次数 + + AcceptCondList []*QuestCond // 领取条件 + FinishCondList []*QuestCond // 完成条件 + FailCondList []*QuestCond // 失败条件 } func (g *GameDataConfig) loadQuestData() { g.QuestDataMap = make(map[int32]*QuestData) - data := g.readCsvFileData("QuestData.csv") - var questDataList []*QuestData - err := csvutil.Unmarshal(data, &questDataList) - if err != nil { - info := fmt.Sprintf("parse file error: %v", err) - panic(info) - } - for _, questData := range questDataList { - // list -> map - g.QuestDataMap[questData.QuestId] = questData + fileNameList := []string{"QuestData.csv", "QuestData_Exported.csv"} + for _, fileName := range fileNameList { + data := g.readCsvFileData(fileName) + var questDataList []*QuestData + err := csvutil.Unmarshal(data, &questDataList) + if err != nil { + info := fmt.Sprintf("parse file error: %v", err) + panic(info) + } + for _, questData := range questDataList { + // list -> map + // 领取条件 + questData.AcceptCondList = make([]*QuestCond, 0) + if questData.AcceptCondType1 != 0 { + paramList := make([]int32, 0) + if questData.AcceptCondType1Param1 != 0 { + paramList = append(paramList, questData.AcceptCondType1Param1) + } + if questData.AcceptCondType1Param2 != 0 { + paramList = append(paramList, questData.AcceptCondType1Param2) + } + if questData.AcceptCondType1Param3 != 0 { + paramList = append(paramList, questData.AcceptCondType1Param3) + } + questData.AcceptCondList = append(questData.AcceptCondList, &QuestCond{ + Type: questData.AcceptCondType1, + Param: paramList, + }) + } + if questData.AcceptCondType2 != 0 { + paramList := make([]int32, 0) + if questData.AcceptCondType2Param1 != 0 { + paramList = append(paramList, questData.AcceptCondType2Param1) + } + if questData.AcceptCondType2Param2 != 0 { + paramList = append(paramList, questData.AcceptCondType2Param2) + } + if questData.AcceptCondType2Param3 != 0 { + paramList = append(paramList, questData.AcceptCondType2Param3) + } + questData.AcceptCondList = append(questData.AcceptCondList, &QuestCond{ + Type: questData.AcceptCondType2, + Param: paramList, + }) + } + if questData.AcceptCondType3 != 0 { + paramList := make([]int32, 0) + if questData.AcceptCondType3Param1 != 0 { + paramList = append(paramList, questData.AcceptCondType3Param1) + } + if questData.AcceptCondType3Param2 != 0 { + paramList = append(paramList, questData.AcceptCondType3Param2) + } + if questData.AcceptCondType3Param3 != 0 { + paramList = append(paramList, questData.AcceptCondType3Param3) + } + questData.AcceptCondList = append(questData.AcceptCondList, &QuestCond{ + Type: questData.AcceptCondType3, + Param: paramList, + }) + } + // 完成条件 + questData.FinishCondList = make([]*QuestCond, 0) + if questData.FinishCondType1 != 0 { + paramList := make([]int32, 0) + if questData.FinishCondType1Param1 != 0 { + paramList = append(paramList, questData.FinishCondType1Param1) + } + if questData.FinishCondType1Param2 != 0 { + paramList = append(paramList, questData.FinishCondType1Param2) + } + questData.FinishCondList = append(questData.FinishCondList, &QuestCond{ + Type: questData.FinishCondType1, + Param: paramList, + ComplexParam: questData.FinishCondType1ComplexParam, + Count: questData.FinishCondType1Count, + }) + } + if questData.FinishCondType2 != 0 { + paramList := make([]int32, 0) + if questData.FinishCondType2Param1 != 0 { + paramList = append(paramList, questData.FinishCondType2Param1) + } + if questData.FinishCondType2Param2 != 0 { + paramList = append(paramList, questData.FinishCondType2Param2) + } + questData.FinishCondList = append(questData.FinishCondList, &QuestCond{ + Type: questData.FinishCondType2, + Param: paramList, + ComplexParam: questData.FinishCondType2ComplexParam, + Count: questData.FinishCondType2Count, + }) + } + if questData.FinishCondType3 != 0 { + paramList := make([]int32, 0) + if questData.FinishCondType3Param1 != 0 { + paramList = append(paramList, questData.FinishCondType3Param1) + } + if questData.FinishCondType3Param2 != 0 { + paramList = append(paramList, questData.FinishCondType3Param2) + } + questData.FinishCondList = append(questData.FinishCondList, &QuestCond{ + Type: questData.FinishCondType3, + Param: paramList, + ComplexParam: questData.FinishCondType3ComplexParam, + Count: questData.FinishCondType3Count, + }) + } + // 失败条件 + g.QuestDataMap[questData.QuestId] = questData + } } logger.Info("QuestData count: %v", len(g.QuestDataMap)) } -func GetQuestDataById(sceneId int32) *QuestData { - return CONF.QuestDataMap[sceneId] +func GetQuestDataById(questId int32) *QuestData { + return CONF.QuestDataMap[questId] } func GetQuestDataMap() map[int32]*QuestData { diff --git a/gdconf/table_struct_mapping.json b/gdconf/table_struct_mapping.json index 3c041e4c..38f30795 100644 --- a/gdconf/table_struct_mapping.json +++ b/gdconf/table_struct_mapping.json @@ -1263,5 +1263,275 @@ "origin_name": "[失败条件]3次数" } ] + }, + { + "table_name": "QuestData_Exported", + "field_list": [ + { + "field_name": "QuestId", + "field_type": "int32", + "origin_name": "子任务ID" + }, + { + "field_name": "ParentQuestId", + "field_type": "int32", + "origin_name": "父任务ID" + }, + { + "field_name": "Sequence", + "field_type": "int32", + "origin_name": "序列" + }, + { + "field_name": "AcceptCondCompose", + "field_type": "int32", + "origin_name": "[领取条件]组合" + }, + { + "field_name": "AcceptCondType1", + "field_type": "int32", + "origin_name": "[领取条件]1类型" + }, + { + "field_name": "AcceptCondType1Param1", + "field_type": "int32", + "origin_name": "[领取条件]1参数1" + }, + { + "field_name": "AcceptCondType1Param2", + "field_type": "int32", + "origin_name": "[领取条件]1参数2" + }, + { + "field_name": "AcceptCondType1Param3", + "field_type": "int32", + "origin_name": "[领取条件]1参数3" + }, + { + "field_name": "AcceptCondType2", + "field_type": "int32", + "origin_name": "[领取条件]2类型" + }, + { + "field_name": "AcceptCondType2Param1", + "field_type": "int32", + "origin_name": "[领取条件]2参数1" + }, + { + "field_name": "AcceptCondType2Param2", + "field_type": "int32", + "origin_name": "[领取条件]2参数2" + }, + { + "field_name": "AcceptCondType2Param3", + "field_type": "int32", + "origin_name": "[领取条件]2参数3" + }, + { + "field_name": "AcceptCondType3", + "field_type": "int32", + "origin_name": "[领取条件]3类型" + }, + { + "field_name": "AcceptCondType3Param1", + "field_type": "int32", + "origin_name": "[领取条件]3参数1" + }, + { + "field_name": "AcceptCondType3Param2", + "field_type": "int32", + "origin_name": "[领取条件]3参数2" + }, + { + "field_name": "AcceptCondType3Param3", + "field_type": "int32", + "origin_name": "[领取条件]3参数3" + }, + { + "field_name": "FinishCondCompose", + "field_type": "int32", + "origin_name": "[完成条件]组合" + }, + { + "field_name": "FinishCondType1", + "field_type": "int32", + "origin_name": "[完成条件]1类型" + }, + { + "field_name": "FinishCondType1Param1", + "field_type": "int32", + "origin_name": "[完成条件]1参数1" + }, + { + "field_name": "FinishCondType1Param2", + "field_type": "int32", + "origin_name": "[完成条件]1参数2" + }, + { + "field_name": "FinishCondType1ComplexParam", + "field_type": "string", + "origin_name": "[完成条件]1复杂参数" + }, + { + "field_name": "FinishCondType1Count", + "field_type": "int32", + "origin_name": "[完成条件]1次数" + }, + { + "field_name": "FinishCondType2", + "field_type": "int32", + "origin_name": "[完成条件]2类型" + }, + { + "field_name": "FinishCondType2Param1", + "field_type": "int32", + "origin_name": "[完成条件]2参数1" + }, + { + "field_name": "FinishCondType2Param2", + "field_type": "int32", + "origin_name": "[完成条件]2参数2" + }, + { + "field_name": "FinishCondType2ComplexParam", + "field_type": "string", + "origin_name": "[完成条件]2复杂参数" + }, + { + "field_name": "FinishCondType2Count", + "field_type": "int32", + "origin_name": "[完成条件]2次数" + }, + { + "field_name": "FinishCondType3", + "field_type": "int32", + "origin_name": "[完成条件]3类型" + }, + { + "field_name": "FinishCondType3Param1", + "field_type": "int32", + "origin_name": "[完成条件]3参数1" + }, + { + "field_name": "FinishCondType3Param2", + "field_type": "int32", + "origin_name": "[完成条件]3参数2" + }, + { + "field_name": "FinishCondType3ComplexParam", + "field_type": "string", + "origin_name": "[完成条件]3复杂参数" + }, + { + "field_name": "FinishCondType3Count", + "field_type": "int32", + "origin_name": "[完成条件]3次数" + }, + { + "field_name": "FailCondCompose", + "field_type": "int32", + "origin_name": "[失败条件]组合" + }, + { + "field_name": "FailCondType1", + "field_type": "int32", + "origin_name": "[失败条件]1类型" + }, + { + "field_name": "FailCondType1Param1", + "field_type": "int32", + "origin_name": "[失败条件]1参数1" + }, + { + "field_name": "FailCondType1Param2", + "field_type": "int32", + "origin_name": "[失败条件]1参数2" + }, + { + "field_name": "FailCondType1ComplexParam", + "field_type": "string", + "origin_name": "[失败条件]1复杂参数" + }, + { + "field_name": "FailCondType1Count", + "field_type": "int32", + "origin_name": "[失败条件]1次数" + }, + { + "field_name": "FailCondType2", + "field_type": "int32", + "origin_name": "[失败条件]2类型" + }, + { + "field_name": "FailCondType2Param1", + "field_type": "int32", + "origin_name": "[失败条件]2参数1" + }, + { + "field_name": "FailCondType2Param2", + "field_type": "int32", + "origin_name": "[失败条件]2参数2" + }, + { + "field_name": "FailCondType2ComplexParam", + "field_type": "string", + "origin_name": "[失败条件]2复杂参数" + }, + { + "field_name": "FailCondType2Count", + "field_type": "int32", + "origin_name": "[失败条件]2次数" + }, + { + "field_name": "FailCondType3", + "field_type": "int32", + "origin_name": "[失败条件]3类型" + }, + { + "field_name": "FailCondType3Param1", + "field_type": "int32", + "origin_name": "[失败条件]3参数1" + }, + { + "field_name": "FailCondType3Param2", + "field_type": "int32", + "origin_name": "[失败条件]3参数2" + }, + { + "field_name": "FailCondType3ComplexParam", + "field_type": "string", + "origin_name": "[失败条件]3复杂参数" + }, + { + "field_name": "FailCondType3Count", + "field_type": "int32", + "origin_name": "[失败条件]3次数" + } + ] + }, + { + "table_name": "TriggerData", + "field_list": [ + { + "field_name": "TriggerId", + "field_type": "int32", + "origin_name": "ID" + }, + { + "field_name": "SceneId", + "field_type": "int32", + "origin_name": "场景ID" + }, + { + "field_name": "GroupId", + "field_type": "int32", + "origin_name": "组ID" + }, + { + "field_name": "TriggerName", + "field_type": "string", + "origin_name": "触发器" + } + ] } ] diff --git a/gdconf/trigger_data.go b/gdconf/trigger_data.go new file mode 100644 index 00000000..f4e86074 --- /dev/null +++ b/gdconf/trigger_data.go @@ -0,0 +1,40 @@ +package gdconf + +import ( + "fmt" + + "hk4e/pkg/logger" + + "github.com/jszwec/csvutil" +) + +// TriggerData 场景LUA触发器配置表 +type TriggerData struct { + TriggerId int32 `csv:"TriggerId"` // ID + SceneId int32 `csv:"SceneId,omitempty"` // 场景ID + GroupId int32 `csv:"GroupId,omitempty"` // 组ID + TriggerName string `csv:"TriggerName,omitempty"` // 触发器 +} + +func (g *GameDataConfig) loadTriggerData() { + g.TriggerDataMap = make(map[int32]*TriggerData) + data := g.readCsvFileData("TriggerData.csv") + var triggerDataList []*TriggerData + err := csvutil.Unmarshal(data, &triggerDataList) + if err != nil { + info := fmt.Sprintf("parse file error: %v", err) + panic(info) + } + for _, triggerData := range triggerDataList { + g.TriggerDataMap[triggerData.TriggerId] = triggerData + } + logger.Info("TriggerData count: %v", len(g.TriggerDataMap)) +} + +func GetTriggerDataById(triggerId int32) *TriggerData { + return CONF.TriggerDataMap[triggerId] +} + +func GetTriggerDataMap() map[int32]*TriggerData { + return CONF.TriggerDataMap +} diff --git a/gs/game/player_login.go b/gs/game/player_login.go index 0e9225c7..31cb7594 100644 --- a/gs/game/player_login.go +++ b/gs/game/player_login.go @@ -148,6 +148,7 @@ func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq g.SendMsg(cmd.PlayerStoreNotify, userId, clientSeq, g.PacketPlayerStoreNotify(player)) g.SendMsg(cmd.AvatarDataNotify, userId, clientSeq, g.PacketAvatarDataNotify(player)) g.SendMsg(cmd.OpenStateUpdateNotify, userId, clientSeq, g.PacketOpenStateUpdateNotify()) + g.SendMsg(cmd.QuestListNotify, userId, clientSeq, g.PacketQuestListNotify(player)) // g.GCGLogin(player) // 发送GCG登录相关的通知包 playerLoginRsp := &proto.PlayerLoginRsp{ IsUseAbilityHash: true, @@ -160,45 +161,6 @@ func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq TotalTickTime: 0.0, } g.SendMsg(cmd.PlayerLoginRsp, userId, clientSeq, playerLoginRsp) - - questListNotify := &proto.QuestListNotify{ - QuestList: make([]*proto.Quest, 0), - } - - for _, questDataConfig := range gdconf.GetQuestDataMap() { - if questDataConfig.QuestId == 35104 { - questListNotify.QuestList = append(questListNotify.QuestList, &proto.Quest{ - QuestId: 35104, - State: 2, - StartTime: uint32(time.Now().Unix()), - ParentQuestId: 351, - StartGameTime: 438, - AcceptTime: uint32(time.Now().Unix()), - FinishProgressList: []uint32{0}, - }) - continue - } - finishProgressList := make([]uint32, 0) - if questDataConfig.FinishCondType1 != 0 { - finishProgressList = append(finishProgressList, 0) - } - if questDataConfig.FinishCondType2 != 0 { - finishProgressList = append(finishProgressList, 0) - } - if questDataConfig.FinishCondType3 != 0 { - finishProgressList = append(finishProgressList, 0) - } - questListNotify.QuestList = append(questListNotify.QuestList, &proto.Quest{ - QuestId: uint32(questDataConfig.QuestId), - State: 1, - StartTime: uint32(time.Now().Unix()), - ParentQuestId: uint32(questDataConfig.ParentQuestId), - StartGameTime: 0, - AcceptTime: uint32(time.Now().Unix()), - FinishProgressList: finishProgressList, - }) - } - g.SendMsg(cmd.QuestListNotify, userId, clientSeq, questListNotify) } func (g *GameManager) PacketPlayerDataNotify(player *model.Player) *proto.PlayerDataNotify { @@ -432,5 +394,7 @@ func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvata player.ChatMsgMap = make(map[uint32][]*model.ChatMsg) + g.AcceptQuest(player, false) + return player } diff --git a/gs/game/player_quest.go b/gs/game/player_quest.go new file mode 100644 index 00000000..f33279cb --- /dev/null +++ b/gs/game/player_quest.go @@ -0,0 +1,157 @@ +package game + +import ( + "hk4e/common/constant" + "hk4e/gdconf" + "hk4e/gs/model" + "hk4e/pkg/logger" + "hk4e/protocol/cmd" + "hk4e/protocol/proto" + + pb "google.golang.org/protobuf/proto" +) + +// AddQuestContentProgressReq 添加任务内容进度请求 +func (g *GameManager) AddQuestContentProgressReq(player *model.Player, payloadMsg pb.Message) { + req := payloadMsg.(*proto.AddQuestContentProgressReq) + logger.Error("AddQuestContentProgressReq: %v", req) + + g.AddQuestProgress(player, req) + + rsp := &proto.AddQuestContentProgressRsp{ + ContentType: req.ContentType, + } + g.SendMsg(cmd.AddQuestContentProgressRsp, player.PlayerID, player.ClientSeq, rsp) + + g.AcceptQuest(player, true) +} + +// AddQuestProgress 添加任务进度 +func (g *GameManager) AddQuestProgress(player *model.Player, req *proto.AddQuestContentProgressReq) { + dbQuest := player.GetDbQuest() + updateQuestIdList := make([]uint32, 0) + for _, quest := range dbQuest.GetQuestMap() { + questDataConfig := gdconf.GetQuestDataById(int32(quest.QuestId)) + if questDataConfig == nil { + logger.Error("get quest data config is nil, questId: %v", quest.QuestId) + continue + } + for index, finishCond := range questDataConfig.FinishCondList { + if len(finishCond.Param) != 1 { + continue + } + if req.ContentType != uint32(finishCond.Type) || req.Param != uint32(finishCond.Param[0]) { + continue + } + dbQuest.AddQuestProgress(quest.QuestId, index, req.AddProgress) + updateQuestIdList = append(updateQuestIdList, quest.QuestId) + } + } + for _, questId := range updateQuestIdList { + quest := dbQuest.GetQuestById(questId) + if quest == nil { + logger.Error("get quest is nil, questId: %v", quest.QuestId) + continue + } + ntf := &proto.QuestProgressUpdateNotify{ + QuestId: quest.QuestId, + FinishProgressList: quest.FinishProgressList, + } + g.SendMsg(cmd.QuestProgressUpdateNotify, player.PlayerID, player.ClientSeq, ntf) + } +} + +// AcceptQuest 接取当前条件下能接取到的全部任务 +func (g *GameManager) AcceptQuest(player *model.Player, isNtfClient bool) { + dbQuest := player.GetDbQuest() + addQuestIdList := make([]uint32, 0) + for _, questData := range gdconf.GetQuestDataMap() { + if dbQuest.GetQuestById(uint32(questData.QuestId)) != nil { + continue + } + canAccept := true + for _, acceptCond := range questData.AcceptCondList { + switch acceptCond.Type { + case constant.QUEST_ACCEPT_COND_TYPE_QUEST_STATE_EQ: + // 某个任务状态等于 参数1:任务id 参数2:任务状态 + if len(acceptCond.Param) != 2 { + logger.Error("quest accept cond config format error, questId: %v", questData.QuestId) + canAccept = false + break + } + quest := dbQuest.GetQuestById(uint32(acceptCond.Param[0])) + if quest == nil { + canAccept = false + break + } + if quest.State != uint32(acceptCond.Param[1]) { + canAccept = false + break + } + default: + canAccept = false + break + } + } + if canAccept { + dbQuest.AddQuest(uint32(questData.QuestId)) + // TODO 判断任务是否能开始执行 + dbQuest.ExecQuest(uint32(questData.QuestId)) + addQuestIdList = append(addQuestIdList, uint32(questData.QuestId)) + } + } + if isNtfClient { + ntf := &proto.QuestListUpdateNotify{ + QuestList: make([]*proto.Quest, 0), + } + for _, questId := range addQuestIdList { + pbQuest := g.PacketQuest(player, questId) + if pbQuest == nil { + continue + } + ntf.QuestList = append(ntf.QuestList, pbQuest) + } + g.SendMsg(cmd.QuestListUpdateNotify, player.PlayerID, player.ClientSeq, ntf) + } +} + +// PacketQuest 打包一个任务 +func (g *GameManager) PacketQuest(player *model.Player, questId uint32) *proto.Quest { + dbQuest := player.GetDbQuest() + questDataConfig := gdconf.GetQuestDataById(int32(questId)) + if questDataConfig == nil { + logger.Error("get quest data config is nil, questId: %v", questId) + return nil + } + quest := dbQuest.GetQuestById(questId) + if quest == nil { + logger.Error("get quest is nil, questId: %v", quest.QuestId) + return nil + } + pbQuest := &proto.Quest{ + QuestId: quest.QuestId, + State: quest.State, + StartTime: quest.StartTime, + ParentQuestId: uint32(questDataConfig.ParentQuestId), + StartGameTime: 0, + AcceptTime: quest.AcceptTime, + FinishProgressList: quest.FinishProgressList, + } + return pbQuest +} + +// PacketQuestListNotify 打包任务列表通知 +func (g *GameManager) PacketQuestListNotify(player *model.Player) *proto.QuestListNotify { + questListNotify := &proto.QuestListNotify{ + QuestList: make([]*proto.Quest, 0), + } + dbQuest := player.GetDbQuest() + for _, quest := range dbQuest.GetQuestMap() { + pbQuest := g.PacketQuest(player, quest.QuestId) + if pbQuest == nil { + continue + } + questListNotify.QuestList = append(questListNotify.QuestList, pbQuest) + } + return questListNotify +} diff --git a/gs/game/route_manager.go b/gs/game/route_manager.go index 658b203d..a252fc16 100644 --- a/gs/game/route_manager.go +++ b/gs/game/route_manager.go @@ -138,6 +138,7 @@ func (r *RouteManager) initRoute() { r.registerRouter(cmd.AvatarPromoteGetRewardReq, GAME_MANAGER.AvatarPromoteGetRewardReq) r.registerRouter(cmd.SetEquipLockStateReq, GAME_MANAGER.SetEquipLockStateReq) r.registerRouter(cmd.TakeoffEquipReq, GAME_MANAGER.TakeoffEquipReq) + r.registerRouter(cmd.AddQuestContentProgressReq, GAME_MANAGER.AddQuestContentProgressReq) } func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) { diff --git a/gs/model/db_quest.go b/gs/model/db_quest.go new file mode 100644 index 00000000..7d509354 --- /dev/null +++ b/gs/model/db_quest.go @@ -0,0 +1,132 @@ +package model + +import ( + "time" + + "hk4e/common/constant" + "hk4e/gdconf" + "hk4e/pkg/logger" +) + +// DbQuest 玩家任务数据 +type DbQuest struct { + QuestMap map[uint32]*Quest // 任务列表 key:任务id value:任务 +} + +// Quest 任务 +type Quest struct { + QuestId uint32 // 任务id + State uint32 // 任务状态 + AcceptTime uint32 // 接取时间 + StartTime uint32 // 开始执行时间 + FinishProgressList []uint32 // 任务进度 +} + +func (p *Player) GetDbQuest() *DbQuest { + if p.DbQuest == nil { + p.DbQuest = &DbQuest{ + QuestMap: make(map[uint32]*Quest), + } + } + return p.DbQuest +} + +// GetQuestMap 获取全部任务 +func (q *DbQuest) GetQuestMap() map[uint32]*Quest { + return q.QuestMap +} + +// GetQuestById 获取一个任务 +func (q *DbQuest) GetQuestById(questId uint32) *Quest { + return q.QuestMap[questId] +} + +// AddQuest 添加一个任务 +func (q *DbQuest) AddQuest(questId uint32) { + _, exist := q.QuestMap[questId] + if exist { + logger.Error("quest is already exist, questId: %v", questId) + return + } + questDataConfig := gdconf.GetQuestDataById(int32(questId)) + if questDataConfig == nil { + logger.Error("get quest data config is nil, questId: %v", questId) + return + } + q.QuestMap[questId] = &Quest{ + QuestId: uint32(questDataConfig.QuestId), + State: constant.QUEST_STATE_TYPE_ACCEPT, + AcceptTime: uint32(time.Now().Unix()), + StartTime: 0, + FinishProgressList: nil, + } +} + +// ExecQuest 开始执行一个任务 +func (q *DbQuest) ExecQuest(questId uint32) { + quest, exist := q.QuestMap[questId] + if !exist { + logger.Error("get quest is nil, questId: %v", questId) + return + } + if quest.State != constant.QUEST_STATE_TYPE_ACCEPT { + logger.Error("invalid quest state, questId: %v, state: %v", questId, quest.State) + return + } + questDataConfig := gdconf.GetQuestDataById(int32(questId)) + if questDataConfig == nil { + logger.Error("get quest data config is nil, questId: %v", questId) + return + } + quest.State = constant.QUEST_STATE_TYPE_EXEC + quest.StartTime = uint32(time.Now().Unix()) + quest.FinishProgressList = make([]uint32, len(questDataConfig.FinishCondList)) +} + +// DeleteQuest 删除一个任务 +func (q *DbQuest) DeleteQuest(questId uint32) { + _, exist := q.QuestMap[questId] + if !exist { + logger.Error("quest is not exist, questId: %v", questId) + return + } + delete(q.QuestMap, questId) +} + +// AddQuestProgress 添加一个任务的进度 +func (q *DbQuest) AddQuestProgress(questId uint32, index int, progress uint32) { + quest, exist := q.QuestMap[questId] + if !exist { + logger.Error("get quest is nil, questId: %v", questId) + return + } + if quest.State != constant.QUEST_STATE_TYPE_EXEC { + logger.Error("invalid quest state, questId: %v, state: %v", questId, quest.State) + return + } + questDataConfig := gdconf.GetQuestDataById(int32(questId)) + if questDataConfig == nil { + logger.Error("get quest data config is nil, questId: %v", questId) + return + } + if index >= len(quest.FinishProgressList) || index >= len(questDataConfig.FinishCondList) { + logger.Error("invalid quest progress index, questId: %v, index: %v", questId, index) + return + } + quest.FinishProgressList[index] += progress + if quest.FinishProgressList[index] >= uint32(questDataConfig.FinishCondList[index].Count) { + quest.State = constant.QUEST_STATE_TYPE_FINISH + } +} + +// ForceFinishQuest 强制完成一个任务 +func (q *DbQuest) ForceFinishQuest(questId uint32) { + questDataConfig := gdconf.GetQuestDataById(int32(questId)) + if questDataConfig == nil { + logger.Error("get quest data config is nil, questId: %v", questId) + return + } + for index, finishCond := range questDataConfig.FinishCondList { + q.AddQuestProgress(questId, index, uint32(finishCond.Count)) + } +} diff --git a/gs/model/player.go b/gs/model/player.go index f93e40ec..94350402 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -54,6 +54,7 @@ type Player struct { MainCharAvatarId uint32 // 主角id GCGInfo *GCGInfo // 七圣召唤信息 IsGM uint8 // 管理员权限等级 + DbQuest *DbQuest // 任务 // 在线数据 请随意 记得加忽略字段的tag LastSaveTime uint32 `bson:"-" msgpack:"-"` // 上一次保存时间 EnterSceneToken uint32 `bson:"-" msgpack:"-"` // 玩家的世界进入令牌