user.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package novicewelfare
  2. import (
  3. "bet24.com/log"
  4. "bet24.com/servers/common"
  5. pb "bet24.com/servers/micros/activityservice/proto"
  6. dotservice "bet24.com/servers/micros/dotservice/proto"
  7. inventory "bet24.com/servers/micros/item_inventory/proto"
  8. notification "bet24.com/servers/micros/notification/proto"
  9. task "bet24.com/servers/micros/task/proto"
  10. "encoding/json"
  11. "strconv"
  12. "time"
  13. )
  14. const (
  15. idle_seconds = 900 // 过期时长(秒)
  16. )
  17. type userTask struct {
  18. userId int // 用户id
  19. finalPackageClaimed bool // 最终礼包领取
  20. taskList []*pb.UserNoviceTaskSchedule // 任务列表
  21. timeStamp int // 当前时间戳
  22. endChan chan int
  23. }
  24. func newUserTask(userId int) *userTask {
  25. ret := new(userTask)
  26. ret.userId = userId
  27. ret.endChan = make(chan int)
  28. ret.loadData()
  29. ret.doCheck()
  30. ret.updateTimeStamp()
  31. return ret
  32. }
  33. // 是否过期
  34. func (ut *userTask) isExpire() bool {
  35. return ut.timeStamp < common.GetTimeStamp()
  36. }
  37. // 更新时间戳
  38. func (ut *userTask) updateTimeStamp() {
  39. ut.timeStamp = common.GetTimeStamp() + idle_seconds
  40. return
  41. }
  42. // 加载数据
  43. func (ut *userTask) loadData() {
  44. ut.taskList = transGetUserTaskList(ut.userId)
  45. if len(ut.taskList) == 0 {
  46. ut.createNoviceTasks()
  47. ut.noviceWelfareChangeNotice()
  48. return
  49. }
  50. if transGetUserBigAwardStatus(ut.userId) > 0 {
  51. ut.finalPackageClaimed = true
  52. }
  53. if ut.isEnd() {
  54. ut.taskList = []*pb.UserNoviceTaskSchedule{}
  55. return
  56. }
  57. ut.checkTaskUnlocking()
  58. }
  59. // 创建新手任务
  60. func (ut *userTask) createNoviceTasks() {
  61. for k, v := range mgr.getSysNoviceTasks() {
  62. var status, unlockDayIndex int
  63. if k == 0 {
  64. status = pb.TaskStatus_Uncompleted
  65. unlockDayIndex = common.GetDayIndex(common.GetTimeStamp())
  66. }
  67. taskInfo := &pb.UserNoviceTaskSchedule{
  68. DayIndex: v.DayIndex,
  69. Scheduled: 0,
  70. Status: status,
  71. UnlockDayIndex: unlockDayIndex,
  72. }
  73. ut.taskList = append(ut.taskList, taskInfo)
  74. ut.updateUserTask(taskInfo)
  75. }
  76. return
  77. }
  78. // 轮询检查
  79. func (ut *userTask) doCheck() {
  80. ticker := time.NewTicker(10 * time.Minute)
  81. go func(t *time.Ticker) {
  82. for {
  83. select {
  84. case <-ut.endChan:
  85. t.Stop()
  86. return
  87. case <-t.C:
  88. // 每十分钟执行一次
  89. ut.checkActivityExpire()
  90. }
  91. }
  92. }(ticker)
  93. }
  94. // 析构,停止计时器等
  95. func (ut *userTask) destructor() {
  96. defer func() {
  97. if recover() != nil {
  98. log.Release("userTask.destructor panic on close chan")
  99. }
  100. }()
  101. close(ut.endChan)
  102. }
  103. // 检查活动过期
  104. func (ut *userTask) checkActivityExpire() {
  105. if len(ut.taskList) == 0 {
  106. //ut.destructor()
  107. return
  108. }
  109. if !ut.isEnd() {
  110. return
  111. }
  112. ut.taskList = []*pb.UserNoviceTaskSchedule{}
  113. ut.noviceWelfareChangeNotice()
  114. //ut.destructor()
  115. return
  116. }
  117. // 是否结束
  118. func (ut *userTask) isEnd() bool {
  119. if len(ut.taskList) == 0 {
  120. return true
  121. }
  122. return common.GetDayIndex(common.GetTimeStamp()) >= ut.taskList[0].UnlockDayIndex+mgr.getActivityDuration()
  123. }
  124. // 检查任务解锁
  125. func (ut *userTask) checkTaskUnlocking() {
  126. taskLen := len(ut.taskList) - 1
  127. unlockDayIndex := common.GetDayIndex(common.GetTimeStamp())
  128. for i := taskLen; i >= 0; i-- {
  129. if ut.taskList[i].Status == pb.TaskStatus_Locked {
  130. continue
  131. }
  132. if ut.taskList[i].UnlockDayIndex == unlockDayIndex {
  133. return
  134. }
  135. if taskLen == i {
  136. return
  137. }
  138. ut.taskList[i+1].UnlockDayIndex = unlockDayIndex
  139. ut.taskList[i+1].Status = pb.TaskStatus_Uncompleted
  140. ut.updateUserTask(ut.taskList[i+1])
  141. ut.noviceWelfareChangeNotice()
  142. return
  143. }
  144. }
  145. // 获取剩余天数
  146. func (ut *userTask) getDaysRemaining() int {
  147. if len(ut.taskList) == 0 {
  148. return 0
  149. }
  150. toDayIndex := common.GetDayIndex(common.GetTimeStamp())
  151. endDayIndex := ut.taskList[0].UnlockDayIndex + mgr.getActivityDuration()
  152. daysRemaining := endDayIndex - toDayIndex
  153. if daysRemaining <= 0 {
  154. return 0
  155. }
  156. return daysRemaining
  157. }
  158. // 获取用户新手福利
  159. func (ut *userTask) getUserNoviceWelfare() pb.UserNoviceWelfare {
  160. var resp pb.UserNoviceWelfare
  161. resp.DaysRemaining = ut.getDaysRemaining()
  162. resp.IsFinalPackage = ut.finalPackageClaimed
  163. resp.Schedule = ut.taskList
  164. return resp
  165. }
  166. // 获取用户任务
  167. func (ut *userTask) getUserTask(dayIndex int) *pb.UserNoviceTaskSchedule {
  168. for k, v := range ut.taskList {
  169. if v.DayIndex != dayIndex {
  170. continue
  171. }
  172. return ut.taskList[k]
  173. }
  174. return nil
  175. }
  176. // 领取新手福利奖励
  177. func (ut *userTask) claimNoviceWelfareAward(dayIndex int, isFinalPackage bool) bool {
  178. if ut.isEnd() {
  179. // 活动已结束
  180. return false
  181. }
  182. if isFinalPackage {
  183. if ut.finalPackageClaimed {
  184. return false
  185. }
  186. if !ut.isFinalPackageClaimable() {
  187. return false
  188. }
  189. ut.finalPackageClaimed = true
  190. go transUpdateUserBigAward(ut.userId)
  191. inventory.AddItems(ut.userId,
  192. mgr.getGiftPacks(),
  193. "Novice Welfare Gift Packs",
  194. common.LOGTYPE_NOVICE_WELFARE_AWARD)
  195. ut.noviceWelfareChangeNotice()
  196. return true
  197. }
  198. config := mgr.getNoviceTaskConfig(dayIndex)
  199. if config == nil {
  200. log.Debug("userTask.claimNoviceWelfareAward config does not exist! dayIndex[%d] userId[%d]",
  201. dayIndex, ut.userId)
  202. return false
  203. }
  204. taskInfo := ut.getUserTask(dayIndex)
  205. if taskInfo == nil {
  206. log.Debug("userTask.claimNoviceWelfareAward user taskInfo not exist! dayIndex[%d] userId[%d]",
  207. dayIndex, ut.userId)
  208. return false
  209. }
  210. if taskInfo.Status < pb.TaskStatus_Completed || taskInfo.Status == pb.TaskStatus_Claimed {
  211. log.Debug("userTask.claimNoviceWelfareAward Task has been claimed or not completed! dayIndex[%d] status[%d]",
  212. dayIndex, taskInfo.Status)
  213. return false
  214. }
  215. if config.Target != taskInfo.Scheduled {
  216. log.Debug("userTask.claimNoviceWelfareAward Condition not satisfied! dayIndex[%d], scheduled[%d]",
  217. dayIndex, taskInfo.Scheduled)
  218. return false
  219. }
  220. taskInfo.Status = pb.TaskStatus_Claimed
  221. ut.updateUserTask(taskInfo)
  222. // 发放道具
  223. inventory.AddItems(ut.userId,
  224. config.Awards,
  225. "Novice Welfare Award",
  226. common.LOGTYPE_NOVICE_WELFARE_AWARD)
  227. ut.noviceWelfareChangeNotice()
  228. // 打点统计
  229. go dotservice.AddDot(ut.userId, dotservice.DotScope{
  230. Scene: dotservice.Scene_NoviceWelfare_Task,
  231. Action: dotservice.Action_Awarded,
  232. Extra: strconv.Itoa(dayIndex),
  233. })
  234. return true
  235. }
  236. // 新手福利变更通知
  237. func (ut *userTask) noviceWelfareChangeNotice() {
  238. d, _ := json.Marshal(ut.getUserNoviceWelfare())
  239. go notification.AddNotification(ut.userId, notification.Notification_NoviceWelfare, string(d))
  240. }
  241. // 是否新手福利提醒
  242. func (ut *userTask) isNoviceWelfareTip() bool {
  243. for _, v := range ut.taskList {
  244. if v.Status == pb.TaskStatus_Completed {
  245. return true
  246. }
  247. }
  248. return false
  249. }
  250. // 最终礼包是否可领取
  251. func (ut *userTask) isFinalPackageClaimable() bool {
  252. for _, v := range ut.taskList {
  253. if v.Status < pb.TaskStatus_Completed {
  254. return false
  255. }
  256. }
  257. return true
  258. }
  259. // 用户动作
  260. func (ut *userTask) doAction(action int, progress int, param task.TaskScope) {
  261. //log.Debug("userTask.doAction user[%d] Have entered. action[%d], progress[%d], param:%+v",
  262. // ut.userId, action, progress, param)
  263. if ut.isEnd() {
  264. // 活动已结束
  265. return
  266. }
  267. var isNotice bool
  268. for _, v := range mgr.getSysNoviceTasks() {
  269. if v.Action != action {
  270. continue
  271. }
  272. if len(v.GameNames) > 0 && !v.IsApplicative(param) {
  273. //log.Debug("userTask.doAction config Parameter mismatch. userId[%d], action[%d], progress[%d], sys:%+v, param:%+v",
  274. // ut.userId, action, progress, v.GameNames, param)
  275. continue
  276. }
  277. taskInfo := ut.getUserTask(v.DayIndex)
  278. if taskInfo == nil {
  279. log.Debug("userTask.doAction Task does not exist! userId[%d], action[%d], progress[%d], dayIndex[%d], param:%+v",
  280. ut.userId, action, progress, v.DayIndex, param)
  281. continue
  282. }
  283. if taskInfo.Status == pb.TaskStatus_Locked || taskInfo.Status >= pb.TaskStatus_Completed {
  284. continue
  285. }
  286. taskInfo.Scheduled += progress
  287. if taskInfo.Scheduled < v.Target {
  288. isNotice = true
  289. ut.updateUserTask(taskInfo)
  290. continue
  291. }
  292. if len(v.Awards) == 0 {
  293. taskInfo.Status = pb.TaskStatus_Claimed
  294. } else {
  295. taskInfo.Status = pb.TaskStatus_Completed
  296. // 打点统计
  297. go dotservice.AddDot(ut.userId, dotservice.DotScope{
  298. Scene: dotservice.Scene_NoviceWelfare_Task,
  299. Action: dotservice.Action_Complete,
  300. Extra: strconv.Itoa(v.DayIndex),
  301. })
  302. }
  303. isNotice = true
  304. taskInfo.Scheduled = v.Target
  305. ut.updateUserTask(taskInfo)
  306. }
  307. if isNotice {
  308. ut.noviceWelfareChangeNotice()
  309. }
  310. }
  311. // 更新用户任务
  312. func (ut *userTask) updateUserTask(taskInfo *pb.UserNoviceTaskSchedule) {
  313. go transUpdateUserTask(ut.userId, taskInfo)
  314. }
  315. func (ut *userTask) dump() {
  316. log.Release("timeout timeStamp: [%s]", common.TimeStampToString(int64(ut.timeStamp)))
  317. for _, v := range ut.taskList {
  318. log.Release("DayIndex:[%d], Scheduled[%d], Status[%d], UnlockDayIndex[%d]",
  319. v.DayIndex, v.Scheduled, v.Status, v.UnlockDayIndex)
  320. }
  321. }