package model import ( "fmt" "math" "rocommon/util" "roserver/baseserver/model" "roserver/serverproto" "sort" "strconv" ) type MakeNtfMsgFunc func(uid uint64) interface{} type LiveRoomInterface interface { Update(deltaMS uint32) Join(uid uint64) Leave(uid uint64) GetReady(uid uint64) bool IsReady(uid uint64) bool SendGift(uid uint64, giftId uint32) RoomId() uint32 RoomType() uint32 StageSec() uint32 StageTimerSec() uint32 Stage() uint32 HasPlayer(uid uint64) bool IsFree(uid uint64) bool GiftRank() []*serverproto.LiveRoomPlayerInfo ChatRecords() []*serverproto.LiveRoomChatData GetReadyPlayerInfoList(uid uint64) []*serverproto.LiveRoomPlayerInfo SendChat(senderId uint64, chatContent string) ShowSubmit(uid uint64, data []*serverproto.KeyValueType64) []*serverproto.KeyValueType64 } // 被子类重载函数 type LiveRoomTemplate interface { GetMaxReadyNum(roomType uint32) GetCMDPlayDataList(readyUidList []uint64, uid uint64, cfg *serverproto.LiveRoomTalkCfg) []*serverproto.KeyValueType64 GetShowResultList(readyUidList []uint64, uid uint64) []*serverproto.LiveRoomPlayerInfo GetShowRewardList(readyUidList []uint64, uid uint64) []*serverproto.KeyValueType64 HasShowData() bool GetShowData(readyUidList []uint64, uid uint64) []*serverproto.KeyValueType64 HandleShowSubmit(uid uint64, data []*serverproto.KeyValueType64) []*serverproto.KeyValueType64 GetStageEnterParams(stage uint32) string ReadyStart() ShowStart() CheckIfShowEnd() bool ShowEnd() HandlePlayCMD(cfg *serverproto.LiveRoomTalkCfg) } type TimelineFrame struct { sn int32 talkCfgList []*serverproto.LiveRoomTalkCfg } type LiveRoomSubmitData struct { uid uint64 data *serverproto.KeyValueType64 } type LiveRoom struct { roomId uint32 roomType uint32 uidList []uint64 readyUidList []uint64 chatSN uint64 updateCount uint64 stageTick int32 tickIntervalMS uint32 //1000ms, 100ms stage uint32 roomCfg *serverproto.LiveRoomCfg giftPoint int32 giftRankResetTime uint64 giftRank []*serverproto.LiveRoomPlayerInfo chatRecords []*serverproto.LiveRoomChatData idleTimeline map[int32]*TimelineFrame readyTimeline map[int32]*TimelineFrame showTimeline map[int32]*TimelineFrame resultTimeline map[int32]*TimelineFrame submitDataList []*LiveRoomSubmitData // 函数字段:模拟虚函数 VF_GetMaxReadyNum func(roomType uint32) int VF_GetCMDPlayDataList func(readyUidList []uint64, uid uint64, cfg *serverproto.LiveRoomTalkCfg) []*serverproto.KeyValueType64 VF_GetShowResultList func(readyUidList []uint64, uid uint64) []*serverproto.LiveRoomPlayerInfo VF_GetShowRewardList func(readyUidList []uint64, uid uint64) []*serverproto.KeyValueType64 VF_HasShowData func() bool VF_GetShowData func(readyUidList []uint64, uid uint64) []*serverproto.KeyValueType64 VF_HandleShowSubmit func(uid uint64, data []*serverproto.KeyValueType64) []*serverproto.KeyValueType64 VF_GetStageEnterParams func(stage uint32) string VF_ReadyStart func() VF_ShowStart func() VF_CheckIfShowEnd func() bool VF_ShowEnd func() VF_HandlePlayCMD func(cfg *serverproto.LiveRoomTalkCfg) } func newLiveRoom(roomId uint32, roomType uint32, tickInterval uint32) LiveRoom { liveRoom := LiveRoom{ roomId: roomId, roomType: roomType, uidList: make([]uint64, 0), readyUidList: make([]uint64, 0), chatSN: 0, updateCount: 0, stageTick: 0, tickIntervalMS: tickInterval, stage: LIVEROOM_STAGE_NULL, roomCfg: serverproto.LiveRoomCfgLoader[int32(roomType)], giftPoint: 0, giftRank: make([]*serverproto.LiveRoomPlayerInfo, 0), chatRecords: make([]*serverproto.LiveRoomChatData, 0), } liveRoom.BaseSetVF() liveRoom.BaseInit() return liveRoom } func (self *LiveRoom) BaseSetVF() { self.VF_GetMaxReadyNum = self.GetMaxReadyNum self.VF_GetCMDPlayDataList = self.GetCMDPlayDataList self.VF_GetShowResultList = self.GetShowResultList self.VF_GetShowRewardList = self.GetShowRewardList self.VF_HasShowData = self.HasShowData self.VF_GetShowData = self.GetShowData self.VF_HandleShowSubmit = self.HandleShowSubmit self.VF_GetStageEnterParams = self.GetStageEnterParams self.VF_ReadyStart = self.ReadyStart self.VF_ShowStart = self.ShowStart self.VF_CheckIfShowEnd = self.CheckIfShowEnd self.VF_ShowEnd = self.ShowEnd self.VF_HandlePlayCMD = self.HandlePlayCMD } /*----------------------------------- 重载函数 -----------------------------------*/ func (self *LiveRoom) GetMaxReadyNum(roomType uint32) int { util.InfoF("LiveRoom: GetMaxReadyNum") return 0 } func (self *LiveRoom) GetCMDPlayDataList(readyUidList []uint64, uid uint64, cfg *serverproto.LiveRoomTalkCfg) []*serverproto.KeyValueType64 { return nil } func (self *LiveRoom) GetShowResultList(readyUidList []uint64, uid uint64) []*serverproto.LiveRoomPlayerInfo { return nil } func (self *LiveRoom) GetShowRewardList(readyUidList []uint64, uid uint64) []*serverproto.KeyValueType64 { return nil } func (self *LiveRoom) HasShowData() bool { return false } func (self *LiveRoom) GetShowData(readyUidList []uint64, uid uint64) []*serverproto.KeyValueType64 { return nil } func (self *LiveRoom) HandleShowSubmit(uid uint64, data []*serverproto.KeyValueType64) []*serverproto.KeyValueType64 { return nil } func (self *LiveRoom) GetStageEnterParams(stage uint32) string { return "" } func (self *LiveRoom) ReadyStart() {} func (self *LiveRoom) ShowStart() {} func (self *LiveRoom) CheckIfShowEnd() bool { return false } func (self *LiveRoom) ShowEnd() {} func (self *LiveRoom) HandlePlayCMD(cfg *serverproto.LiveRoomTalkCfg) {} /*----------------------------------- 内部函数 -----------------------------------*/ func (self *LiveRoom) BaseInit() { self.idleTimeline = self.CreateTimeline(LIVEROOM_STAGE_IDLE) self.readyTimeline = self.CreateTimeline(LIVEROOM_STAGE_READY) self.showTimeline = self.CreateTimeline(LIVEROOM_STAGE_SHOW) self.resultTimeline = self.CreateTimeline(LIVEROOM_STAGE_RESULT) self.giftRankResetTime = util.GetCurrentTime() time1 := self.CalcTimelineSec(self.idleTimeline) time2 := self.CalcTimelineSec(self.readyTimeline) time3 := self.CalcTimelineSec(self.showTimeline) time4 := self.CalcTimelineSec(self.resultTimeline) util.InfoF("GetTimelineTime: ", time1, time2, time3, time4) self.ChangeStage(LIVEROOM_STAGE_IDLE) } func (self *LiveRoom) CreateTimeline(stage int32) map[int32]*TimelineFrame { timeline := make(map[int32]*TimelineFrame, 0) var currentSN int32 = 0 liveRoomTalkCfg := serverproto.LiveRoomTalkCfgLoader for i := 1; i <= len(liveRoomTalkCfg); i++ { cfg := liveRoomTalkCfg[int32(i)] if uint32(cfg.Type) == self.roomType && cfg.Stage == stage { if frame, exist := timeline[currentSN]; exist { frame.talkCfgList = append(frame.talkCfgList, cfg) } else { newFrame := &TimelineFrame{sn: currentSN, talkCfgList: make([]*serverproto.LiveRoomTalkCfg, 0)} newFrame.talkCfgList = append(newFrame.talkCfgList, cfg) timeline[currentSN] = newFrame } currentSN += cfg.Time } } return timeline } func (self *LiveRoom) CalcTimelineSec(timeline map[int32]*TimelineFrame) int32 { var totalTime int32 = 0 for _, frame := range timeline { totalTime += frame.talkCfgList[0].Time } return totalTime } func (self *LiveRoom) Update(deltaMS uint32) { self.updateCount += 1 if self.updateCount*uint64(deltaMS) > math.MaxUint64-10000 { self.updateCount = 1 } if (self.updateCount*uint64(deltaMS))%uint64(self.tickIntervalMS) == 0 { switch self.stage { case LIVEROOM_STAGE_IDLE: self.LIVEROOM_STAGE_IDLE_Update(self.tickIntervalMS) case LIVEROOM_STAGE_READY: self.LIVEROOM_STAGE_READY_Update(self.tickIntervalMS) case LIVEROOM_STAGE_SHOW: self.LIVEROOM_STAGE_SHOW_Update(self.tickIntervalMS) case LIVEROOM_STAGE_RESULT: self.LIVEROOM_STAGE_RESULT_Update(self.tickIntervalMS) } self.stageTick += 1 } if model.IsDailyResetHour5(self.giftRankResetTime) { self.giftRank = make([]*serverproto.LiveRoomPlayerInfo, 0) self.giftRankResetTime = util.GetCurrentTime() util.InfoF("ResetGiftRank: RoomType=%d, time=%d", self.roomType, self.giftRankResetTime) } } func (self *LiveRoom) ChangeStage(newStage uint32) { self.stageTick = 0 // 1. Current Stage Exit switch self.stage { case LIVEROOM_STAGE_IDLE: self.LIVEROOM_STAGE_IDLE_Exit() case LIVEROOM_STAGE_READY: self.LIVEROOM_STAGE_READY_Exit() case LIVEROOM_STAGE_SHOW: self.LIVEROOM_STAGE_SHOW_Exit() case LIVEROOM_STAGE_RESULT: self.LIVEROOM_STAGE_RESULT_Exit() } // 2. Next Stage Enter switch newStage { case LIVEROOM_STAGE_IDLE: self.LIVEROOM_STAGE_IDLE_Enter() case LIVEROOM_STAGE_READY: self.LIVEROOM_STAGE_READY_Enter() case LIVEROOM_STAGE_SHOW: self.LIVEROOM_STAGE_SHOW_Enter() case LIVEROOM_STAGE_RESULT: self.LIVEROOM_STAGE_RESULT_Enter() } self.SendAllPlayers(func(uid uint64) interface{} { return &serverproto.SCLiveRoomStageNtf{ Uid: uid, RoomId: self.roomId, Stage: newStage, StageTimerSec: self.GetStageTimerSec(newStage), StageParams: self.VF_GetStageEnterParams(newStage), } }) // 3. Update Current Stage self.stage = newStage } func (self *LiveRoom) HandleCMD(sn int32, cfg *serverproto.LiveRoomTalkCfg) { switch cfg.CMD { case LIVEROOM_CMD_TALK: self.SendAllPlayers(func(uid uint64) interface{} { return &serverproto.SCLiveRoomCMDTalkNtf{ Uid: uid, RoomId: self.roomId, TalkId: uint32(cfg.Id), TalkParams: "", } }) case LIVEROOM_CMD_PLAY: self.VF_HandlePlayCMD(cfg) self.SendAllPlayers(func(uid uint64) interface{} { return &serverproto.SCLiveRoomCMDPlayNtf{ Uid: uid, RoomId: self.roomId, PlayDataList: self.VF_GetCMDPlayDataList(self.readyUidList, uid, cfg), } }) } } /*----------------------------------- Stage: IDLE -----------------------------------*/ func (self *LiveRoom) LIVEROOM_STAGE_IDLE_Enter() { util.InfoF("LIVEROOM_STAGE_IDLE_Enter") self.readyUidList = make([]uint64, 0) self.submitDataList = make([]*LiveRoomSubmitData, 0) self.giftPoint = 0 } func (self *LiveRoom) LIVEROOM_STAGE_IDLE_Update(deltaMS uint32) { if self.stageTick >= self.CalcTimelineSec(self.idleTimeline) { if self.giftPoint >= serverproto.LiveRoomCfgLoader[int32(self.roomType)].MaxGiftPoint { self.ChangeStage(LIVEROOM_STAGE_READY) } else { self.ChangeStage(LIVEROOM_STAGE_IDLE) } return } //util.InfoF("LIVEROOM_STAGE_IDLE_Update: Tick %d", uint32(self.stageTick)) if frame, exist := self.idleTimeline[self.stageTick]; exist { for i := 0; i < len(frame.talkCfgList); i++ { cfg := frame.talkCfgList[i] self.HandleCMD(frame.sn, cfg) } } } func (self *LiveRoom) LIVEROOM_STAGE_IDLE_Exit() {} /*----------------------------------- Stage: READY -----------------------------------*/ func (self *LiveRoom) LIVEROOM_STAGE_READY_Enter() { util.InfoF("LIVEROOM_STAGE_READY_Enter") self.VF_ReadyStart() } func (self *LiveRoom) LIVEROOM_STAGE_READY_Update(deltaMS uint32) { if self.stageTick >= self.CalcTimelineSec(self.readyTimeline) { if len(self.readyUidList) > 0 { self.ChangeStage(LIVEROOM_STAGE_SHOW) } else { self.ChangeStage(LIVEROOM_STAGE_IDLE) } return } //util.InfoF("LIVEROOM_STAGE_READY_Update: Tick %d", uint32(self.stageTick)) if frame, exist := self.readyTimeline[self.stageTick]; exist { for i := 0; i < len(frame.talkCfgList); i++ { cfg := frame.talkCfgList[i] self.HandleCMD(frame.sn, cfg) } } } func (self *LiveRoom) LIVEROOM_STAGE_READY_Exit() {} /*----------------------------------- Stage: SHOW -----------------------------------*/ func (self *LiveRoom) LIVEROOM_STAGE_SHOW_Enter() { util.InfoF("LIVEROOM_STAGE_SHOW_Enter") self.VF_ShowStart() } func (self *LiveRoom) LIVEROOM_STAGE_SHOW_Update(deltaMS uint32) { if self.stageTick >= self.CalcTimelineSec(self.showTimeline) { self.ChangeStage(LIVEROOM_STAGE_RESULT) return } if self.VF_CheckIfShowEnd() { self.ChangeStage(LIVEROOM_STAGE_RESULT) return } //util.InfoF("LIVEROOM_STAGE_SHOW_Update: Tick %d", uint32(self.stageTick)) if frame, exist := self.showTimeline[self.stageTick]; exist { for i := 0; i < len(frame.talkCfgList); i++ { cfg := frame.talkCfgList[i] self.HandleCMD(frame.sn, cfg) } } if self.VF_HasShowData() { self.ShowDataNtf() } } func (self *LiveRoom) LIVEROOM_STAGE_SHOW_Exit() { self.VF_ShowEnd() } /*----------------------------------- Stage: RESULT -----------------------------------*/ func (self *LiveRoom) LIVEROOM_STAGE_RESULT_Enter() { //util.InfoF("LIVEROOM_STAGE_RESULT_Enter") self.SendAllPlayers(func(currUid uint64) interface{} { showResultList := self.VF_GetShowResultList(self.readyUidList, currUid) showRewardList := self.VF_GetShowRewardList(self.readyUidList, currUid) return &serverproto.SCLiveRoomResultNtf{ Uid: currUid, RoomId: self.roomId, PlayerResultList: showResultList, PlayerRewardList: showRewardList, } }) } func (self *LiveRoom) LIVEROOM_STAGE_RESULT_Update(deltaMS uint32) { if self.stageTick >= self.CalcTimelineSec(self.resultTimeline) { self.ChangeStage(LIVEROOM_STAGE_IDLE) return } //util.InfoF("LIVEROOM_STAGE_RESULT_Update: Tick %d", uint32(self.stageTick)) if frame, exist := self.resultTimeline[self.stageTick]; exist { for i := 0; i < len(frame.talkCfgList); i++ { cfg := frame.talkCfgList[i] self.HandleCMD(frame.sn, cfg) } } } func (self *LiveRoom) LIVEROOM_STAGE_RESULT_Exit() {} func (self *LiveRoom) GetStageTimerSec(stage uint32) uint32 { var timeline map[int32]*TimelineFrame switch stage { case LIVEROOM_STAGE_IDLE: timeline = self.idleTimeline case LIVEROOM_STAGE_READY: timeline = self.readyTimeline case LIVEROOM_STAGE_SHOW: timeline = self.showTimeline case LIVEROOM_STAGE_RESULT: timeline = self.resultTimeline } return uint32(self.CalcTimelineSec(timeline)) } func (self *LiveRoom) Join(uid uint64) { if SliceIsExist(self.uidList, uid) == false { self.uidList = append(self.uidList, uid) } player := RoomMgr.GetPlayer(uid) player.LeaveRoom = false player.WaitLeaveRoom = false } func (self *LiveRoom) Leave(uid uint64) { player := RoomMgr.GetPlayer(uid) player.WaitLeaveRoom = true self.uidList = SliceRemoveByValue(self.uidList, uid) } func (self *LiveRoom) IsReady(uid uint64) bool { if SliceIsExist(self.readyUidList, uid) { return true } return false } func (self *LiveRoom) GetReady(currUid uint64) bool { if self.stage != LIVEROOM_STAGE_READY { return false } if SliceIsExist(self.readyUidList, currUid) { return false } if len(self.readyUidList) > self.VF_GetMaxReadyNum(self.roomType) { return false } self.readyUidList = append(self.readyUidList, currUid) self.SendAllPlayers(func(currUid uint64) interface{} { // 给客户端显示自己和其他4个玩家的准备信息 maxCount := 5 readyPlayerInfoList := make([]*serverproto.LiveRoomPlayerInfo, 0) if SliceIsExist(self.readyUidList, currUid) { // 1. 添加当前玩家的信息 currPlayer := RoomMgr.GetPlayer(currUid) readyPlayerInfoList = append(readyPlayerInfoList, &serverproto.LiveRoomPlayerInfo{ Nickname: currPlayer.Name, Level: currPlayer.Level, HeadId: currPlayer.HeadId, HeadTitle: currPlayer.HeadTitle, }) // 2. 先添加其他准备玩家信息 for i := len(self.readyUidList) - 1; i >= 0; i-- { tmpUid := self.readyUidList[i] if tmpUid != currUid { player := RoomMgr.GetPlayer(tmpUid) readyPlayerInfoList = append(readyPlayerInfoList, &serverproto.LiveRoomPlayerInfo{ Nickname: player.Name, Level: player.Level, HeadId: player.HeadId, HeadTitle: player.HeadTitle, }) if len(readyPlayerInfoList) > maxCount-1 { break } } } } else { for i := len(self.readyUidList) - 1; i >= 0; i-- { tmpUid := self.readyUidList[i] player := RoomMgr.GetPlayer(tmpUid) readyPlayerInfoList = append(readyPlayerInfoList, &serverproto.LiveRoomPlayerInfo{ Nickname: player.Name, Level: player.Level, HeadId: player.HeadId, HeadTitle: player.HeadTitle, }) if len(readyPlayerInfoList) > maxCount { break } } } return &serverproto.SCLiveRoomGetReadyNtf{ Uid: currUid, RoomId: self.roomId, ReadyPlayerInfoList: readyPlayerInfoList, } }) if len(self.readyUidList) >= self.VF_GetMaxReadyNum(self.roomType) { self.ChangeStage(LIVEROOM_STAGE_SHOW) } return true } func (self *LiveRoom) RoomId() uint32 { return self.roomId } func (self *LiveRoom) RoomType() uint32 { return self.roomType } func (self *LiveRoom) Stage() uint32 { return self.stage } func (self *LiveRoom) StageTimerSec() uint32 { return self.GetStageTimerSec(self.stage) } func (self *LiveRoom) StageSec() uint32 { return self.GetStageTimerSec(self.stage) - uint32(self.stageTick) } func (self *LiveRoom) HasPlayer(uid uint64) bool { for i := 0; i < len(self.uidList); i++ { if uid == self.uidList[i] { return true } } return false } func (self *LiveRoom) IsFree(uid uint64) bool { if len(self.uidList) > LIVEROOM_MAX_PLAYER_NUM { return false } return true } func (self *LiveRoom) GetReadyPlayerInfoList(uid uint64) []*serverproto.LiveRoomPlayerInfo { readyPlayerInfoList := make([]*serverproto.LiveRoomPlayerInfo, 0) if self.stage == LIVEROOM_STAGE_READY { if SliceIsExist(self.readyUidList, uid) { readyPlayerInfoList = append(readyPlayerInfoList, MakeLiveRoomPlayerInfo(uid)) } for _, readyUid := range self.readyUidList { if len(readyPlayerInfoList) < 5 { readyPlayerInfoList = append(readyPlayerInfoList, MakeLiveRoomPlayerInfo(readyUid)) } } } return readyPlayerInfoList } func (self *LiveRoom) GiftRank() []*serverproto.LiveRoomPlayerInfo { sort.Slice(self.giftRank, func(i, j int) bool { return self.giftRank[i].Data > self.giftRank[j].Data }) topCount := 10 var rank []*serverproto.LiveRoomPlayerInfo if len(self.giftRank) >= topCount { rank = self.giftRank[:topCount] } else { rank = self.giftRank } return rank } func (self *LiveRoom) ChatRecords() []*serverproto.LiveRoomChatData { return self.chatRecords } func (self *LiveRoom) RecordChatData(chatSN uint64, chatData *serverproto.LiveRoomChatData) { var maxChatRecordNum int = 10 if len(self.chatRecords) < maxChatRecordNum { self.chatRecords = append(self.chatRecords, chatData) } else { idx := chatSN % uint64(maxChatRecordNum) self.chatRecords[idx] = chatData } } func (self *LiveRoom) ShowDataNtf() { self.SendAllPlayers(func(uid uint64) interface{} { showData := self.VF_GetShowData(self.readyUidList, uid) return &serverproto.SCLiveRoomShowDataNtf{ Uid: uid, RoomId: self.roomId, ShowDataList: showData, } }) } func (self *LiveRoom) SendChat(senderId uint64, chatContent string) { senderPlayer := RoomMgr.GetPlayer(senderId) self.chatSN = self.chatSN + 1 if self.chatSN >= math.MaxUint64-100 { self.chatSN = 1 } chatData := &serverproto.LiveRoomChatData{ SN: self.chatSN, PlayerInfo: &serverproto.LiveRoomPlayerInfo{ Nickname: senderPlayer.Name, Level: senderPlayer.Level, HeadId: senderPlayer.HeadId, HeadTitle: 1, }, ChatContent: chatContent, } self.RecordChatData(self.chatSN, chatData) self.SendAllPlayers(func(uid uint64) interface{} { return &serverproto.SCLiveRoomChatNtf{ Uid: uid, RoomId: self.roomId, ChatData: chatData, } }) } func (self *LiveRoom) AddItemList(uid uint64, items []*serverproto.KeyValueType, from int32, notify bool) { SendToAllGame(&serverproto.SSGameRoleAddItemListReq{ Uid: uid, ItemList: items, From: from, Notify: notify, }) } func (self *LiveRoom) DeleteItemList(uid uint64, items []*serverproto.KeyValueType, from int32, notify bool) { SendToAllGame(&serverproto.SSGameRoleDeleteItemListReq{ Uid: uid, ItemList: items, From: from, Notify: notify, }) } func (self *LiveRoom) ShowSubmit(uid uint64, data []*serverproto.KeyValueType64) []*serverproto.KeyValueType64 { return self.VF_HandleShowSubmit(uid, data) } func (self *LiveRoom) SendGift(uid uint64, giftId uint32) { player := RoomMgr.GetPlayer(uid) isFind := false currGiftPoint := 1 self.giftPoint += int32(currGiftPoint) for _, v := range self.giftRank { if v.Uid == player.Uid { giftNum, _ := strconv.Atoi(v.Data) giftNum += currGiftPoint isFind = true break } } if isFind == false { playerInfo := MakeLiveRoomPlayerInfo(uid) playerInfo.Data = string(1) self.giftRank = append(self.giftRank, playerInfo) } sort.Slice(self.giftRank, func(i, j int) bool { val1, _ := strconv.Atoi(self.giftRank[i].Data) val2, _ := strconv.Atoi(self.giftRank[j].Data) return val1 > val2 }) sendGiftTalkCfg := serverproto.LiveRoomTalkCfgLoader[LIVEROOM_TYPE_SEND_GIFT] self.SendAllPlayers(func(uid uint64) interface{} { return &serverproto.SCLiveRoomCMDTalkNtf{ Uid: uid, RoomId: self.roomId, TalkId: uint32(sendGiftTalkCfg.Id), TalkParams: fmt.Sprintf("%s:%s", player.Name, giftId), } }) self.SendAllPlayers(func(uid uint64) interface{} { return &serverproto.SCLiveRoomGiftRankNtf{ Uid: uid, GiftRank: self.giftRank[:10], } }) } func (self *LiveRoom) SendAllPlayers(makeNtfMsgFunc MakeNtfMsgFunc) { for i := 0; i < len(self.uidList); i++ { uid := self.uidList[i] ntfMsg := makeNtfMsgFunc(uid) SendToAllGame(ntfMsg) } }