package room import ( "fmt" "math/rand" "samba/pkg/log" "samba/proto" . "samba/server/game/baseroom" . "samba/server/game/player" . "samba/server/truco/service" "samba/stub" "samba/util/model" "samba/util/util" "sort" "time" ) var matchNo = 100000 var GMatchQueue = &MatchQueue{ queues: make(map[int]*RoomTypeQueue), } var GMatchClubQueue = &MatchQueue{ queues: make(map[int]*RoomTypeQueue), clubId: 10000, } // RoomTypeQueue 玩法房间队列 type RoomTypeQueue struct { rooms map[int]*MatchRoom // [roomId]*MatchRoom } type MatchQueue struct { queues map[int]*RoomTypeQueue // [roomType]*MatchRoom clubId int } func (m *MatchQueue) FindRoom(roomId, roomType int) *MatchRoom { if queues, ok := m.queues[roomType]; ok { if matchRoom, ok := queues.rooms[roomId]; ok { return matchRoom } } return nil } func (m *MatchQueue) FindRoomByPlayer(userId int64) *MatchRoom { for _, playTypeQueue := range m.queues { for _, room := range playTypeQueue.rooms { if m.checkPlayerInRoom(userId, room) { return room } } } return nil } func (m *MatchQueue) AddRoom(room *MatchRoom) { roomTypeQueue, ok := m.queues[room.Type()] if !ok { roomTypeQueue = &RoomTypeQueue{ rooms: make(map[int]*MatchRoom), } m.queues[room.Type()] = roomTypeQueue } m.queues[room.Type()].rooms[room.Id()] = room } func (m *MatchQueue) RemoveRoom(roomId, roomType int) { if queues, ok := m.queues[roomType]; ok { delete(queues.rooms, roomId) } } func (m *MatchQueue) checkPlayerInRoom(uid int64, room *MatchRoom) bool { for _, p := range room.player { if p.UID == uid { return true } } return false } // 检查金币是否符合要求 func (m *MatchQueue) checkCoin(user *Player, roomCnf *stub.Room, clubId int) proto.ErrorCode { var coins, takeCoins int64 var err, err1 error op := model.NewUserResourceOp() if clubId == 0 { coins, err = op.Get(user.UID, model.ResCoins) takeCoins, err1 = op.GetTakeCoin(user.UID) } else { //coins, err = op.Load(user.UID, model.ResClubUserScore, clubId) //takeCoins, err1 = op.GetClubTakeCoin(user.UID) } if err1 != nil || err != nil { return proto.Internal } if coins-takeCoins < roomCnf.MinCoin { return proto.NotEnough } if coins-takeCoins > roomCnf.MaxCoin { return proto.RoomCoinLimit } return proto.Ok } func (m *MatchQueue) checkEnterRoom(user *Player, _ int, room *MatchRoom) proto.ErrorCode { if m.checkPlayerInRoom(user.UID, room) { return proto.InRoom } if len(room.Players()) >= room.cnf.MinPlayers { return proto.RoomFull } return proto.Ok } func (m *MatchQueue) makeRoomId(roomType int) int { _ = roomType matchNo++ return matchNo } func (m *MatchQueue) CreateRoom(roomType int) (*MatchRoom, proto.ErrorCode) { m.makeRoomId(roomType) roomCnf, code := stub.FindRoomCnf(roomType) if code != proto.Ok { log.Error(fmt.Sprintf("room type %d not found", roomType)) return nil, proto.Internal } return NewMatchRoom(matchNo, roomCnf), proto.Ok } func (m *MatchQueue) EnterMatchQueue(user *Player, roomType, clubId int) proto.ErrorCode { roomCnf, code := stub.FindRoomCnf(roomType) if code != proto.Ok { return code } playTypeQueue, ok := m.queues[roomType] if !ok { playTypeQueue = &RoomTypeQueue{ rooms: make(map[int]*MatchRoom), } m.queues[roomType] = playTypeQueue } if RoomMgr.FindPlayerCurrentRoom(user.UID) != nil { return proto.InRoom } if code = m.checkCoin(user, roomCnf, clubId); code != proto.Ok { return code } sum, err := user.GetPlayCount(stub.Truco) if err != nil { log.Error("get play count error") } if err == nil && sum <= stub.PlayerNoviceThreshold { // 新手玩家 room, code := m.CreateRoom(roomType) if code == proto.Ok { log.Debug(fmt.Sprintf("user %d 新手玩家,只匹配机器人", user.UID)) // 只匹配机器人 room.SetOnlyMatchRobot() room.AddPlayer(user) playTypeQueue.rooms[room.Id()] = room } return code } var room *MatchRoom for _, rm := range playTypeQueue.rooms { if rm.OnlyMatchRobot() { continue } code = m.checkEnterRoom(user, roomType, rm) if code == proto.Ok { room = rm break } else if code == proto.RoomFull { continue } else { return code } } if room == nil { room, code = m.CreateRoom(roomType) if code == proto.Ok { playTypeQueue.rooms[room.Id()] = room } } if room != nil { log.Debug(fmt.Sprintf("user:%v enter matching queue.room type:%v id:%v", user.UID, roomType, room.Id())) room.AddPlayer(user) } return code } // P为真人,R为机器人,调整玩家位置,形成(P R R R R R) (P P R R R R)(P P P R R R) func (m *MatchQueue) adjustSeat(matchRoom *MatchRoom) { rand.Shuffle(len(matchRoom.player), func(i, j int) { matchRoom.player[i], matchRoom.player[j] = matchRoom.player[j], matchRoom.player[i] }) for _, p := range matchRoom.player { if p.IsRobot() { p.Weight = matchRoom.robotWeight matchRoom.robotWeight += 1 } else { p.Weight = matchRoom.playerWeight matchRoom.playerWeight += 1 } } sort.Slice(matchRoom.player, func(i, j int) bool { return matchRoom.player[i].Weight < matchRoom.player[j].Weight }) } func (m *MatchQueue) Matching() { for _, playTypeQueue := range m.queues { if len(playTypeQueue.rooms) == 0 { continue } for _, room := range playTypeQueue.rooms { if time.Now().Unix()-room.tm.Unix() >= 2 { robotNum := 0 for _, p := range room.player { robotNum += util.Tie(p.IsRobot(), 1, 0) } if len(room.player) < room.cnf.MinPlayers && robotNum < room.cnf.RobotNum { if rand.Int()%100 > 30 { continue } if user := RobotMgr.Pop(room.cnf); user != nil { _ = room.AddPlayer(user) } else { log.Warn(fmt.Sprintf("has not robot")) } } if len(room.player) == room.cnf.MinPlayers { ir, code := RoomMgr.CreateRoom(room.Type(), 0, NewTrucoRoom) if code == proto.Ok { trucoRoom := ir.(*TrucoRoom) m.adjustSeat(room) for _, user := range room.player { trucoRoom.OnEnterRoom(user.Player) log.Debug(fmt.Sprintf("user:%v leave matching queue. ready gaming", user.UID)) } m.RemoveRoom(room.Id(), room.Type()) } } } } } TrucoService.NewTimer(1*time.Second, m.Matching, false, "MatchQueue.Matching") }