package main import ( "math" "strings" "time" "github.com/globalsign/mgo/bson" "mongo.games.com/goserver/core/logger" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/message" ) const ( HorseRaceLampTypeServer = iota HorseRaceLampTypeLottery // 竞技馆抽奖活动中奖消息 HorseRaceLampTypeBatch = 100 // 弹幕跑马灯 ) var HorseRaceLampMgrSingleton = &HorseRaceLampMgr{ HorseRaceLampMsgList: make(map[string]*HorseRaceLamp), HorseRaceLampGameList: make(map[string][]*HorseRaceLamp), HorseRaceLampCastList: make(map[string]*HorseRaceLampCastInfo), NextGameHorseRaceLamp: make(map[string]int64), } type HorseRaceLampMgr struct { HorseRaceLampMsgList map[string]*HorseRaceLamp // _id:所有平台跑马灯数据 HorseRaceLampCastList map[string]*HorseRaceLampCastInfo // 平台:跑马灯(队列跑马灯+弹幕跑马灯) HorseRaceLampGameList map[string][]*HorseRaceLamp // 平台:游戏跑马灯,只播一次,播完删除 NextGameHorseRaceLamp map[string]int64 // 平台:下次游戏跑马灯播放时间 } type HorseRaceLamp struct { Platform string // 平台 Key string // _id Channel string // 包渠道 Title string // 标题 Content string // 内容 StartTime int64 // 开始播放的时间 Interval int32 // 播放间隔 Count int32 // 播放次数 LastTime int64 // 上次播放时间 Priority int32 // 播放优先级 CreateTime int64 // 创建时间 MsgType int32 // 消息类型 State int32 // 状态 0.启用;1.关闭 Players []int32 // 玩家 StandSec int32 // 保持时间 isRob bool // 是否是机器人 limitInterval int32 // 播放需要的时间 } type HorseRaceLampCastInfo struct { CurIndex int // 队列跑马灯当前索引 CurTime int64 // 队列跑马灯当下次检测时间(时间间隔是上一个跑马灯播放需要的时间) DealQueue []*HorseRaceLamp // 队列跑马灯,按顺序播放 DealList []*HorseRaceLamp // 弹幕跑马灯列表 } func (this *HorseRaceLampMgr) InitHorseRaceLamp() { for _, p := range PlatformMgrSingleton.GetPlatforms() { noticeList, err := model.GetAllHorseRaceLamp(p.IdStr) if err != nil { logger.Logger.Error("InitHorseRaceLamp count failed:", err, noticeList) } for _, value := range noticeList { this.AddHorseRaceLampMsg(&HorseRaceLampParam{ Platform: value.Platform, Key: value.Id.Hex(), AppChannel: value.Channel, Title: value.Title, Content: value.Content, StartTime: value.StartTime, Interval: value.Interval, Count: value.Count, MsgType: value.MsgType, State: value.State, Priority: value.Priority, Players: value.Target, StandSec: value.StandSec, }) } } } func (this *HorseRaceLampMgr) insertToCastMsg(msg *HorseRaceLamp) { pKey := msg.Platform if this.HorseRaceLampCastList[pKey] == nil { this.HorseRaceLampCastList[pKey] = &HorseRaceLampCastInfo{ CurIndex: 0, CurTime: 0, DealQueue: []*HorseRaceLamp{}, DealList: []*HorseRaceLamp{}, } } switch msg.MsgType { case HorseRaceLampTypeBatch: this.HorseRaceLampCastList[pKey].DealList = append(this.HorseRaceLampCastList[pKey].DealList, msg) default: this.HorseRaceLampCastList[pKey].DealQueue = append(this.HorseRaceLampCastList[pKey].DealQueue, msg) } } type HorseRaceLampParam struct { Platform string Key string AppChannel string Title string Content string StartTime int64 // 开始时间 Interval int32 // 播放间隔,秒 Count int32 // 播放次数 MsgType int32 // 消息类型 State int32 // 状态 0.启用;1.关闭 Priority int32 // 优先级 Players []int32 // 玩家 StandSec int32 // 保持时间 } // AddHorseRaceLampMsg 添加跑马灯 func (this *HorseRaceLampMgr) AddHorseRaceLampMsg(param *HorseRaceLampParam) string { msg := &HorseRaceLamp{ Key: param.Key, Channel: param.AppChannel, Title: param.Title, Content: param.Content, StartTime: param.StartTime, Interval: param.Interval, Count: param.Count, MsgType: param.MsgType, Priority: param.Priority, CreateTime: time.Now().Unix(), Platform: param.Platform, State: param.State, Players: param.Players, StandSec: param.StandSec, limitInterval: int32(math.Floor(float64(len(param.Content))*0.3)) + 6, } this.HorseRaceLampMsgList[param.Key] = msg this.insertToCastMsg(msg) return param.Key } // EditHorseRaceLampMsg 修改跑马灯 func (this *HorseRaceLampMgr) EditHorseRaceLampMsg(hrl *HorseRaceLamp) bool { if _, ok := this.HorseRaceLampMsgList[hrl.Key]; !ok { return false } hrl.limitInterval = int32(math.Floor(float64(len(hrl.Content))*0.3)) + 6 this.HorseRaceLampMsgList[hrl.Key] = hrl if pInfo, ok := this.HorseRaceLampCastList[hrl.Platform]; ok && hrl.MsgType != HorseRaceLampTypeBatch { pInfo.CurTime = 0 pInfo.CurIndex = 0 } return true } // DelHorseRaceLampMsg 删除跑马灯 func (this *HorseRaceLampMgr) DelHorseRaceLampMsg(key string) { if needDel, ok := this.HorseRaceLampMsgList[key]; ok { if pInfo, ok := this.HorseRaceLampCastList[needDel.Platform]; ok { pInfo.CurTime = 0 pInfo.CurIndex = 0 for index := range pInfo.DealQueue { if pInfo.DealQueue[index] == needDel { pInfo.DealQueue = append(pInfo.DealQueue[:index], pInfo.DealQueue[index+1:]...) break } } for index := range pInfo.DealList { if pInfo.DealList[index] == needDel { pInfo.DealList = append(pInfo.DealList[:index], pInfo.DealList[index+1:]...) break } } } } delete(this.HorseRaceLampMsgList, key) } type GameHorseRaceLampParam struct { Platform string // 平台 AppChannel string // 包渠道 Content string // 内容 MsgType int32 // 消息类型 IsRobot bool // 是否是机器人消息 Priority int32 // 优先级 } // PushGameHorseRaceLamp 推送游戏跑马灯 func (this *HorseRaceLampMgr) PushGameHorseRaceLamp(param *GameHorseRaceLampParam) bool { msg := &HorseRaceLamp{ Platform: param.Platform, Content: param.Content, Count: 1, MsgType: param.MsgType, Priority: param.Priority, limitInterval: int32(math.Floor(float64(len(param.Content))*0.3)) + 6, isRob: param.IsRobot, } platform := param.Platform isRob := param.IsRobot priority := param.Priority if pool, exist := this.HorseRaceLampGameList[platform]; exist { if len(pool) >= model.GameParamData.BacklogGameHorseRaceLamp && len(pool) > 0 { minRobPriority := priority minPlayerPriority := priority bestRobIdx := -1 bestPlayerIdx := -1 for k, v := range pool { if !isRob { if v.isRob { //优先替换机器人的跑马灯 if v.Priority <= minRobPriority { bestRobIdx = k minRobPriority = v.Priority } } else { //其次替换真实玩家的跑马灯 if v.Priority < minPlayerPriority { bestPlayerIdx = k minPlayerPriority = v.Priority } } } else { if v.isRob { if v.Priority < minRobPriority { bestRobIdx = k minRobPriority = v.Priority } } } } if bestRobIdx != -1 { //优先替换机器人的跑马灯 pool = append(pool[:bestRobIdx], pool[bestRobIdx+1:]...) } else if bestPlayerIdx != -1 { //其次替换玩家的跑马灯 pool = append(pool[:bestPlayerIdx], pool[bestPlayerIdx+1:]...) } else { //没找到要替换的,直接丢弃自己的 return false } } if !isRob { // 替换一个机器人的消息,没有机器人则追加 isFindRob := false if len(pool) > 0 { for k, v := range pool { if v.isRob { pool[k] = msg isFindRob = true break } } } if isFindRob { this.HorseRaceLampGameList[platform] = pool } else { this.HorseRaceLampGameList[platform] = append(pool, msg) } } else { // 是机器人直接追加 this.HorseRaceLampGameList[platform] = append(pool, msg) } } else { this.HorseRaceLampGameList[platform] = []*HorseRaceLamp{msg} } return true } // DealHorseRaceLamp 广播跑马灯 func (this *HorseRaceLampMgr) DealHorseRaceLamp(uTime int64, value *HorseRaceLamp) { if value.Count > 0 { // 播放次数 this.BroadcastHorseRaceLampMsg(value) value.Count = value.Count - 1 value.LastTime = uTime value.StartTime = value.LastTime + int64(value.Interval) if value.Count <= 0 { this.DelHorseRaceLampMsg(value.Key) model.RemoveHorseRaceLamp(value.Key, value.Platform) } } else { this.BroadcastHorseRaceLampMsg(value) value.LastTime = uTime value.StartTime = value.LastTime + int64(value.Interval) } } func (this *HorseRaceLampMgr) ModuleName() string { return "HorseRaceLampMgr" } func (this *HorseRaceLampMgr) Init() { //this.InitHorseRaceLamp() } func (this *HorseRaceLampMgr) Update() { uTime := time.Now().Unix() // 队列跑马灯 for _, v := range this.HorseRaceLampCastList { if uTime > v.CurTime { if v.CurIndex < len(v.DealQueue) { value := v.DealQueue[v.CurIndex] //需要跳过 if value.State != 0 { v.CurIndex += 1 if v.CurIndex >= len(v.DealQueue) { v.CurIndex = 0 } } else if uTime > value.StartTime && value.State == 0 { this.DealHorseRaceLamp(uTime, value) v.CurIndex += 1 if v.CurIndex >= len(v.DealQueue) { v.CurIndex = 0 } v.CurTime = uTime + int64(value.limitInterval) } } } } // 弹幕跑马灯 for _, nc := range this.HorseRaceLampCastList { for _, value := range nc.DealList { if uTime > value.StartTime && value.State == 0 { this.DealHorseRaceLamp(uTime, value) } } } // 游戏跑马灯,只播一次 for name, pool := range this.HorseRaceLampGameList { if len(pool) > 0 { msg := pool[0] nextTs := this.NextGameHorseRaceLamp[name] if uTime >= nextTs { this.HorseRaceLampGameList[name] = pool[1:] if msg != nil { this.BroadcastHorseRaceLampMsg(msg) this.NextGameHorseRaceLamp[name] = uTime + int64(msg.limitInterval) } } } } } func (this *HorseRaceLampMgr) SaveHorseRaceLamp() { for _, hrl := range this.HorseRaceLampMsgList { model.EditHorseRaceLamp(&model.HorseRaceLamp{ Id: bson.ObjectIdHex(hrl.Key), Channel: hrl.Channel, Title: hrl.Title, Content: hrl.Content, StartTime: hrl.StartTime, Interval: hrl.Interval, Count: hrl.Count, CreateTime: hrl.CreateTime, Priority: hrl.Priority, MsgType: hrl.MsgType, Platform: hrl.Platform, State: hrl.State, Target: hrl.Players, StandSec: hrl.StandSec, }) } } func (this *HorseRaceLampMgr) Shutdown() { //this.SaveHorseRaceLamp() //module.UnregisteModule(this) } func (this *HorseRaceLampMgr) BroadcastHorseRaceLampMsg(horseRaceLamp *HorseRaceLamp) { if horseRaceLamp.MsgType == HorseRaceLampTypeBatch { logger.Logger.Infof(">>>>>>>弹幕>>>>>>>>(this *HorseRaceLampMgr) BroadcastHorseRaceLampMsg content:%v msgType:%v "+ "players:%v standSec:%v", horseRaceLamp.Content, horseRaceLamp.MsgType, horseRaceLamp.Players, horseRaceLamp.StandSec) } var rawpack = &message.SCNotice{ Count: proto.Int(1), MsgType: proto.Int32(horseRaceLamp.MsgType), Ts: proto.Int64(time.Now().Unix()), //发送时间 ChannelId: proto.String(horseRaceLamp.Channel), Platform: proto.String(horseRaceLamp.Platform), StandSec: proto.Int32(horseRaceLamp.StandSec), } if horseRaceLamp.MsgType == 0 { rawpack.Params = append(rawpack.Params, &message.NoticeParam{StrParam: proto.String(horseRaceLamp.Content)}) } else if horseRaceLamp.MsgType > 0 && horseRaceLamp.MsgType < 100 { strArr := strings.Split(horseRaceLamp.Content, "|") for _, value := range strArr { rawpack.Params = append(rawpack.Params, &message.NoticeParam{StrParam: proto.String(value)}) } } else if horseRaceLamp.MsgType == 100 { rawpack.Params = append(rawpack.Params, &message.NoticeParam{StrParam: proto.String(horseRaceLamp.Title)}) rawpack.Params = append(rawpack.Params, &message.NoticeParam{StrParam: proto.String(horseRaceLamp.Content)}) //rawpack.Params = append(rawpack.Params, &message.NoticeParam{StrParam: proto.String(horseRaceLamp.Footer)}) } proto.SetDefaults(rawpack) if len(horseRaceLamp.Players) == 0 { PlayerMgrSington.BroadcastMessageToPlatform(horseRaceLamp.Platform, int(message.MSGPacketID_PACKET_SC_NOTICE), rawpack) } else { PlayerMgrSington.BroadcastMessageToTarget(horseRaceLamp.Players, int(message.MSGPacketID_PACKET_SC_NOTICE), rawpack) } } func init() { //module.RegisteModule(HorseRaceLampMgrSingleton, time.Second*3, 0) }