samba/server/truco/room/match.go
2025-06-04 09:51:39 +08:00

256 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 RP 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")
}