package handler import ( "bet24.com/log" "bet24.com/servers/common" badge "bet24.com/servers/micros/badge/proto" dotservice "bet24.com/servers/micros/dotservice/proto" highly_profitable "bet24.com/servers/micros/highly_profitable/proto" inventory "bet24.com/servers/micros/item_inventory/proto" item "bet24.com/servers/micros/item_inventory/proto" notification "bet24.com/servers/micros/notification/proto" pb "bet24.com/servers/micros/task/proto" userlabel "bet24.com/servers/micros/userlabel/proto" "encoding/json" "fmt" "math/rand" "sort" "strconv" "sync" ) func isExpired(ut *pb.UserTask) bool { if ut.Start == 0 || ut.Duration == 0 { return false } now := common.GetTimeStamp() // 当天任务 if ut.Duration == pb.TaskDuration_Daily { return !common.IsSameDay(now, ut.Start) } // 本周任务 if ut.Duration == pb.TaskDuration_Weekly { return !common.IsSameWeek(now, ut.Start) } return (now - ut.Start) > ut.Duration } func isStart(ut *pb.UserTask) bool { return common.GetTimeStamp() >= ut.Start } func resetUserTask(ut *pb.UserTask) { ut.Scheduled = 0 ut.Status = pb.TaskStatus_active ut.Start = common.GetTimeStamp() ut.Scheduled = 0 t := mgr.getSysTask(ut.TaskId) if t == nil { return } ut.Duration = t.Duration } type user_task struct { lock *sync.RWMutex userId int task_list map[int]*pb.UserTask } func newUserTask(userId int) *user_task { ret := new(user_task) ret.lock = &sync.RWMutex{} ret.task_list = make(map[int]*pb.UserTask) ret.userId = userId go ret.loadUserTask() return ret } func (ut *user_task) loadUserTask() { // log.Debug("user_task.loadUserTask[%d]", ut.userId) needUpdate := false // 从数据库加载正在完成的任务 tasks := getUserTaskList(ut.userId) // 检查是否已失效,并且有周期则重新开始 for k, v := range tasks { t := mgr.getSysTask(v.TaskId) if t == nil { delete(tasks, k) go removeUserTask(ut.userId, k) continue } if v.Scheduled > t.Target { v.Scheduled = t.Target } if !isExpired(v) { continue } else { // 如果是转盘任务,并且已失效,则删除 if common.DecimalAnd(pb.TaskScene_DailyWheel, t.Scene) > 0 { if v.Status != pb.TaskStatus_active { delete(tasks, k) go removeUserTask(ut.userId, k) } else { // 重置时间 v.Start = common.GetTimeStamp() v.Scheduled = 0 } needUpdate = true continue } } if !isStart(v) { continue } if !t.Repeatable { v.Status = pb.TaskStatus_expired needUpdate = true continue } if t.PreTask != 0 { delete(tasks, k) go removeUserTask(ut.userId, k) } else { // log.Debug("user_task.loadUserTask reset task %d,%d", ut.userId, v.TaskId) resetUserTask(v) } needUpdate = true } ut.lock.Lock() ut.task_list = tasks ut.lock.Unlock() //log.Debug("user_task.loadUserTask1") //mgr.dumpUser(fmt.Sprintf("%d", ut.userId)) // 检查是否需要主动创建任务 if ut.createTasks() { needUpdate = true } //log.Debug("user_task.loadUserTask2") //mgr.dumpUser(fmt.Sprintf("%d", ut.userId)) if needUpdate { ut.updateToDBAll() } } func (ut *user_task) getTaskList() []*pb.UserTask { var ret []*pb.UserTask ut.lock.RLock() defer ut.lock.RUnlock() for _, v := range ut.task_list { if v.Status > pb.TaskStatus_awarded { continue } ret = append(ret, v) } return ret } func (ut *user_task) awardTaskWithItems(taskId int) string { ok, _ := ut.awardTask(taskId) if !ok { return "" } t := mgr.getSysTask(taskId) if t == nil { log.Debug("user_task.awardTaskWithItems userId[%d] taskId[%d] systask not found", ut.userId, taskId) return "" } d, _ := json.Marshal(t.Awards) return string(d) } func (ut *user_task) awardTask(taskId int) (bool, string) { ut.lock.Lock() task, ok := ut.task_list[taskId] if !ok { log.Debug("user_task.awardTask userId[%d] taskId[%d] not found", ut.userId, taskId) ut.lock.Unlock() return false, "任务不存在" } if task.Status != pb.TaskStatus_complete { log.Debug("user_task.awardTask userId[%d] taskId[%d] not completed status[%d]", ut.userId, taskId, task.Status) ut.lock.Unlock() return false, "任务未完成或已领取" } task.Status = pb.TaskStatus_awarded ut.lock.Unlock() t := mgr.getSysTask(taskId) if t == nil { log.Debug("user_task.awardTask userId[%d] taskId[%d] systask not found", ut.userId, taskId) } else { go ut.sendAward(t.Awards, fmt.Sprintf("TaskId[%d] award", taskId)) // 6=任务类(任务模块)(用户标签) go userlabel.TriggerEvent(ut.userId, userlabel.Type_Task, userlabel.Scope{Num: 1}) // 徽章进度 go badge.DoAction(ut.userId, badge.Action_CompleteTheTask, 1, badge.Scope{TaskId: taskId}) } go ut.updateToDB(task) // 重复任务在登录时检测并创建 // 打点统计 go dotservice.AddDot(ut.userId, dotservice.DotScope{ Scene: dotservice.Scene_Task, Action: dotservice.Action_Awarded, Extra: strconv.Itoa(taskId), }) // 检测是否生成后续任务 ut.checkNextTask(taskId) return true, "" } func (ut *user_task) checkNextTask(taskId int) { nextTasks := mgr.getNextTasks(taskId) if len(nextTasks) == 0 { return } for _, v := range nextTasks { ut.generateUserTask(v) } } func (ut *user_task) generateUserTask(task *pb.Task) { ut.lock.RLock() _, ok := ut.task_list[task.Id] ut.lock.RUnlock() if ok { //log.Debug("user_task.generateUserTask taskId[%d] already exist", task.Id) return } userTask := &pb.UserTask{ TaskId: task.Id, Scheduled: 0, Status: pb.TaskStatus_active, } if task.Duration != 0 { userTask.Start = common.GetTimeStamp() userTask.Duration = task.Duration } ut.lock.Lock() ut.task_list[task.Id] = userTask ut.lock.Unlock() //log.Debug("user_task.generateUserTask %d,%d", ut.userId, task.Id) go ut.updateToDB(userTask) } func (ut *user_task) updateToDBAll() { ut.lock.RLock() defer ut.lock.RUnlock() for _, v := range ut.task_list { go ut.updateToDB(v) } } func (ut *user_task) updateToDB(userTask *pb.UserTask) { updateUserTask(ut.userId, userTask) } func (ut *user_task) sendAward(items []item.ItemPack, desc string) { for _, v := range items { tool := item.GetItem(v.ItemId) if tool == nil { log.Release("user_task.sendAward itemId[%d] not exist", v.ItemId) continue } //判断是否是活跃度,不是的话,继续下一个 if tool.Type != item.Item_Vitality { continue } //触发日活跃度任务 go ut.doTaskAction(pb.TaskAction_day_vitality, v.Count, pb.TaskScope{}) //触发周活跃度任务 go ut.doTaskAction(pb.TaskAction_week_vitality, v.Count, pb.TaskScope{}) } //加道具 inventory.AddItems(ut.userId, items, desc, common.LOGTYPE_TASK_AWARD) } func (ut *user_task) createTasks() bool { ret := false tasklist := mgr.getSysTaskList() for _, v := range tasklist { ut.lock.RLock() _, ok := ut.task_list[v.Id] ut.lock.RUnlock() if ok { continue } if v.PreTask != 0 { continue } if !ut.isAutoGenerate(v.Scene) { continue } ut.generateUserTask(v) ret = true } return ret } func (ut *user_task) isAutoGenerate(scene int) bool { if scene == 0 { return true } if common.DecimalAnd(scene, pb.TaskScene_Hall) > 0 { return true } if common.DecimalAnd(scene, pb.TaskScene_Game) > 0 { return true } if common.DecimalAnd(scene, pb.TaskScene_AudioRoom) > 0 { return true } return false } func (ut *user_task) createTasksByIds(taskIds []int) bool { ret := false tasklist := mgr.getSysTasksByTaskIds(taskIds) if len(tasklist) == 0 { return false } // 特定的任务,需要删除老任务 if tasklist[0].Scene >= pb.TaskScene_HighlyProfitable { ut.removeTaskByScene(tasklist[0].Scene) } for _, v := range tasklist { ut.lock.RLock() _, ok := ut.task_list[v.Id] ut.lock.RUnlock() if ok { continue } if v.PreTask != 0 { continue } // 代理会员任务,绑码时触发 if v.Scene == pb.TaskScene_Agent { continue } // 每日转盘任务随机生成 if common.DecimalAnd(v.Scene, pb.TaskScene_DailyWheel) > 0 { continue } ut.generateUserTask(v) ret = true } return ret } func (ut *user_task) createRandomTasksByScene(scene int, maxCount int, isRefresh bool) { // 先获取我的任务 existTasks := ut.getTasksByScene(scene) // 不刷新 if !isRefresh && len(existTasks) >= maxCount { return } var toChangeTaskIds []int var finishedTasks []int for _, v := range existTasks { if v.Status == pb.TaskStatus_active { toChangeTaskIds = append(toChangeTaskIds, v.TaskId) } else { finishedTasks = append(finishedTasks, v.TaskId) } } if isRefresh { maxCount -= len(finishedTasks) } else { maxCount -= len(toChangeTaskIds) } // 如果是刷新,则删除未完成任务 if len(toChangeTaskIds) > 0 && isRefresh { // 删除这些任务 ut.lock.Lock() for _, v := range toChangeTaskIds { delete(ut.task_list, v) go removeUserTask(ut.userId, v) } ut.lock.Unlock() } // 如果不是刷新,则删除已完成任务 if len(finishedTasks) > 0 && !isRefresh { // 删除这些任务 ut.lock.Lock() for _, v := range finishedTasks { delete(ut.task_list, v) go removeUserTask(ut.userId, v) } ut.lock.Unlock() } if maxCount <= 0 { return } // 创建任务 targetTasks := mgr.getSysTasksByScene(scene) // 把已完成的清理出去 targetTasks = ut.removeSysTaskByTaskIds(targetTasks, finishedTasks) // 把要换掉的任务去掉 targetTasks = ut.removeSysTaskByTaskIds(targetTasks, toChangeTaskIds) // 取部分 targetTasks = ut.getRandomTasks(targetTasks, maxCount) // 创建 for _, v := range targetTasks { //log.Debug("createRandomTasksByScene UserId[%d] Scene[%d] TaskId[%d]", ut.userId, scene, v.Id) ut.generateUserTask(v) } } func (ut *user_task) isAllTaskFinished(scene int) bool { // 先获取我的任务 existTasks := ut.getTasksByScene(scene) if len(existTasks) == 0 { return false } for _, v := range existTasks { if v.Status == pb.TaskStatus_active { return false } } return true } func (ut *user_task) isTasksFinished(taskIds []int) bool { // 先获取我的任务 ut.lock.RLock() defer ut.lock.RUnlock() for _, taskId := range taskIds { v, ok := ut.task_list[taskId] if !ok { return false } if v.Status == pb.TaskStatus_active { return false } } return true } func (ut *user_task) getRandomElements(array []int, count int) []int { if len(array) <= count { return array } rand.Shuffle(len(array), func(i, j int) { array[i], array[j] = array[j], array[i] }) return array[:count] } func (ut *user_task) getRandomTasks(array []*pb.Task, count int) []*pb.Task { if len(array) <= count { return array } rand.Shuffle(len(array), func(i, j int) { array[i], array[j] = array[j], array[i] }) return array[:count] } func (ut *user_task) removeSysTaskByTaskIds(sysTasks []*pb.Task, taskIds []int) []*pb.Task { for i := 0; i < len(sysTasks); { toRemove := false for _, v := range taskIds { if v == sysTasks[i].Id { toRemove = true break } } if toRemove { sysTasks = append(sysTasks[:i], sysTasks[i+1:]...) } else { i++ } } return sysTasks } func (ut *user_task) getTasksByScene(scene int) []*pb.UserTask { var ret []*pb.UserTask ut.lock.RLock() for k, v := range ut.task_list { t := mgr.getSysTask(v.TaskId) if t == nil { log.Release("user_task.getTasksByScene scene[%d] taskId[%d] not found systask", scene, v.TaskId) continue } if common.DecimalAnd(t.Scene, scene) == 0 { continue } ret = append(ret, ut.task_list[k]) } ut.lock.RUnlock() return ret } // 放弃任务 func (ut *user_task) isActionTaskActive(action int, param pb.TaskScope) bool { ut.lock.Lock() defer ut.lock.Unlock() for _, v := range ut.task_list { if v.Status != pb.TaskStatus_active { continue } if isExpired(v) { continue } if !isStart(v) { continue } t := mgr.getSysTask(v.TaskId) if t == nil { log.Debug("user_task.doTaskAction taskId %d not found", v.TaskId) continue } if t.Action != action { continue } if !t.IsAplicable(param) { continue } return true } return false } // 放弃任务 func (ut *user_task) removeTaskByAction(action int, param pb.TaskScope) { ut.lock.Lock() defer ut.lock.Unlock() for _, v := range ut.task_list { if v.Status != pb.TaskStatus_active { continue } if isExpired(v) { continue } if !isStart(v) { continue } t := mgr.getSysTask(v.TaskId) if t == nil { log.Debug("user_task.removeTaskByAction taskId %d not found", v.TaskId) continue } if t.Action != action { continue } if !t.IsAplicable(param) { continue } v.Status = pb.TaskStatus_expired go ut.updateToDB(v) } } // 放弃任务 func (ut *user_task) removeTaskByScene(scene int) { var toRemove []int ut.lock.RLock() for k, v := range ut.task_list { t := mgr.getSysTask(v.TaskId) if t == nil { log.Debug("user_task.removeTaskByScene taskId %d not found", v.TaskId) continue } if t.Scene != scene { continue } toRemove = append(toRemove, k) } ut.lock.RUnlock() if len(toRemove) == 0 { return } log.Debug("removeTaskByScene %d,%d removing %v", ut.userId, scene, toRemove) ut.lock.Lock() for _, v := range toRemove { delete(ut.task_list, v) go removeUserTask(ut.userId, v) } ut.lock.Unlock() } // 用户的动作,看是否触发任务完成,返回是否需要刷新任务,任务进度变化或者状态变化都需要刷新 func (ut *user_task) doTaskAction(action int, progress int, param pb.TaskScope) (bool, int) { if action == pb.TaskAction_earn { //log.Debug("user_task.doTaskAction UserId[%d],action[%d],progress[%d]", ut.userId, action, progress) } ut.lock.Lock() defer ut.lock.Unlock() ret := false taskId := 0 for _, v := range ut.task_list { if v.Status != pb.TaskStatus_active { continue } if isExpired(v) { continue } if !isStart(v) { continue } t := mgr.getSysTask(v.TaskId) if t == nil { log.Debug("user_task.doTaskAction taskId %d not found", v.TaskId) continue } if t.Action != action { continue } if !t.IsAplicable(param) { continue } v.Scheduled += progress needNotification := false if v.Scheduled >= t.Target { if common.DecimalOr(pb.TaskScene_HighlyProfitable, t.Scene) > 0 { highly_profitable.OnUserFinishedRelativeTask(ut.userId) } if len(t.Awards) == 0 { v.Status = pb.TaskStatus_awarded } else { v.Status = pb.TaskStatus_complete // 打点统计 go dotservice.AddDot(ut.userId, dotservice.DotScope{ Scene: dotservice.Scene_Task, Action: dotservice.Action_Complete, Extra: strconv.Itoa(v.TaskId), }) } v.Scheduled = t.Target needNotification = true taskId = v.TaskId } else { if pb.TaskAction_play_time != action { needNotification = true } } if needNotification { d, _ := json.Marshal(v) go notification.AddNotification(ut.userId, notification.Notification_Task, string(d)) } ret = true go ut.updateToDB(v) } return ret, taskId } func (ut *user_task) isTriggerPreAddiction() bool { ut.lock.RLock() defer ut.lock.RUnlock() t, ok := ut.task_list[pb.PreAddictionTaskId] if !ok { return false } return t.Status >= pb.TaskStatus_complete } // 返回各场景对应的标识是否有任务完成 func (ut *user_task) getTaskTipScene() int { var scene int ut.lock.RLock() defer ut.lock.RUnlock() for _, v := range ut.task_list { if v.Status != pb.TaskStatus_complete { continue } sysTask := mgr.getSysTask(v.TaskId) if sysTask == nil { continue } // 场景任务提醒 scene = common.DecimalOr(scene, sysTask.Scene) } return scene } func (ut *user_task) awardAllTask() []item.ItemPack { var ret []item.ItemPack ut.lock.Lock() for _, v := range ut.task_list { if v.Status != pb.TaskStatus_complete { continue } sysTask := mgr.getSysTask(v.TaskId) if sysTask == nil { continue } // 一键领取所有任务屏蔽非大厅和游戏任务 if common.DecimalAnd(pb.TaskScene_Hall+pb.TaskScene_Game, sysTask.Scene) == 0 { continue } ret = append(ret, sysTask.Awards...) v.Status = pb.TaskStatus_awarded go ut.updateToDB(v) // 检测是否生成后续任务 go ut.checkNextTask(v.TaskId) // 徽章进度 go badge.DoAction(ut.userId, badge.Action_CompleteTheTask, 1, badge.Scope{TaskId: v.TaskId}) // 打点统计 go dotservice.AddDot(ut.userId, dotservice.DotScope{ Scene: dotservice.Scene_Task, Action: dotservice.Action_Awarded, Extra: strconv.Itoa(v.TaskId), }) } ut.lock.Unlock() ret = item.GroupItems(ret) if len(ret) > 0 { ut.sendAward(ret, "awardAllTask") } return ret } func (ut *user_task) claimTaskRewards(taskIds []int) []item.ItemPack { //log.Debug("user_task.claimTaskRewards userId[%d] taskIds%v", ut.userId, taskIds) var ret []item.ItemPack ut.lock.Lock() for _, taskId := range taskIds { v, ok := ut.task_list[taskId] if !ok { continue } if v.Status != pb.TaskStatus_complete { continue } sysTask := mgr.getSysTask(v.TaskId) if sysTask == nil { continue } ret = append(ret, sysTask.Awards...) v.Status = pb.TaskStatus_awarded go ut.updateToDB(v) // 检测是否生成后续任务 go ut.checkNextTask(v.TaskId) // 徽章进度 go badge.DoAction(ut.userId, badge.Action_CompleteTheTask, 1, badge.Scope{TaskId: v.TaskId}) // 打点统计 go dotservice.AddDot(ut.userId, dotservice.DotScope{ Scene: dotservice.Scene_Task, Action: dotservice.Action_Awarded, Extra: strconv.Itoa(v.TaskId), }) } ut.lock.Unlock() ret = item.GroupItems(ret) if len(ret) > 0 { ut.sendAward(ret, "claimTaskRewards") } return ret } func (ut *user_task) dump() { ut.lock.RLock() var list []*pb.UserTask for k := range ut.task_list { list = append(list, ut.task_list[k]) } ut.lock.RUnlock() sort.Slice(list, func(i, j int) bool { return list[i].TaskId < list[j].TaskId }) for _, v := range list { ut.dumpUserTask(v) } } func (ut *user_task) dumpUserTask(v *pb.UserTask) { if v.Start > 0 { log.Release(" [%d]:Sched[%d]Sta[%s]St[%s]Dur[%s]", v.TaskId, v.Scheduled, pb.GetTaskStatusDesc(v.Status), common.TimeStampToShortString(int64(v.Start)), pb.GetTaskDurationDesc(v.Duration)) } else { log.Release(" [%d]:Sched[%d]Sta[%s]", v.TaskId, v.Scheduled, pb.GetTaskStatusDesc(v.Status)) } }