samba/server/truco/room/match.go

256 lines
6.2 KiB
Go
Raw Normal View History

2025-06-04 09:51:39 +08:00
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")
}