feat: 新增PVP匹配队列分组和暗黑门关卡前置检查
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

This commit is contained in:
xinian
2026-04-23 14:48:34 +08:00
parent 5500684e29
commit 57676e998f
6 changed files with 87 additions and 19 deletions

View File

@@ -21,17 +21,25 @@ type PVPMatchJoinPayload struct {
Nick string `json:"nick"`
FightMode uint32 `json:"fightMode"`
Status uint32 `json:"status"`
IsVip uint32 `json:"isVip"`
IsDebug uint8 `json:"isDebug"`
CatchTimes []uint32 `json:"catchTimes"`
}
type pvpMatchQueueKey struct {
FightMode uint32
IsVip uint32
IsDebug uint8
}
type pvpMatchCoordinator struct {
mu sync.Mutex
queues map[uint32][]pvpwire.QueuePlayerSnapshot
queues map[pvpMatchQueueKey][]pvpwire.QueuePlayerSnapshot
lastSeen map[uint32]time.Time
}
var defaultPVPMatchCoordinator = &pvpMatchCoordinator{
queues: make(map[uint32][]pvpwire.QueuePlayerSnapshot),
queues: make(map[pvpMatchQueueKey][]pvpwire.QueuePlayerSnapshot),
lastSeen: make(map[uint32]time.Time),
}
@@ -51,6 +59,8 @@ func (m *pvpMatchCoordinator) JoinOrUpdate(payload PVPMatchJoinPayload) error {
Nick: payload.Nick,
FightMode: payload.FightMode,
Status: payload.Status,
IsVip: payload.IsVip,
IsDebug: payload.IsDebug,
JoinedAtUnix: now.Unix(),
CatchTimes: append([]uint32(nil), payload.CatchTimes...),
}
@@ -62,11 +72,12 @@ func (m *pvpMatchCoordinator) JoinOrUpdate(payload PVPMatchJoinPayload) error {
m.removeUserLocked(payload.UserID)
m.lastSeen[payload.UserID] = now
queue := m.queues[payload.FightMode]
queueKey := newPVPMatchQueueKey(player)
queue := m.queues[queueKey]
if len(queue) > 0 {
host := queue[0]
queue = queue[1:]
m.queues[payload.FightMode] = queue
m.queues[queueKey] = queue
delete(m.lastSeen, host.UserID)
delete(m.lastSeen, payload.UserID)
@@ -79,7 +90,7 @@ func (m *pvpMatchCoordinator) JoinOrUpdate(payload PVPMatchJoinPayload) error {
}
match = &result
} else {
m.queues[payload.FightMode] = append(queue, player)
m.queues[queueKey] = append(queue, player)
}
m.mu.Unlock()
@@ -109,7 +120,7 @@ func (m *pvpMatchCoordinator) Cancel(userID uint32) {
}
func (m *pvpMatchCoordinator) pruneExpiredLocked(now time.Time) {
for mode, queue := range m.queues {
for key, queue := range m.queues {
next := make([]pvpwire.QueuePlayerSnapshot, 0, len(queue))
for _, queued := range queue {
last := m.lastSeen[queued.UserID]
@@ -119,12 +130,12 @@ func (m *pvpMatchCoordinator) pruneExpiredLocked(now time.Time) {
}
next = append(next, queued)
}
m.queues[mode] = next
m.queues[key] = next
}
}
func (m *pvpMatchCoordinator) removeUserLocked(userID uint32) {
for mode, queue := range m.queues {
for key, queue := range m.queues {
next := make([]pvpwire.QueuePlayerSnapshot, 0, len(queue))
for _, queued := range queue {
if queued.UserID == userID {
@@ -132,7 +143,15 @@ func (m *pvpMatchCoordinator) removeUserLocked(userID uint32) {
}
next = append(next, queued)
}
m.queues[mode] = next
m.queues[key] = next
}
}
func newPVPMatchQueueKey(player pvpwire.QueuePlayerSnapshot) pvpMatchQueueKey {
return pvpMatchQueueKey{
FightMode: player.FightMode,
IsVip: player.IsVip,
IsDebug: player.IsDebug,
}
}

View File

@@ -3,6 +3,7 @@ package controller
import (
"blazing/common/rpc"
"blazing/common/socket/errorcode"
"blazing/cool"
"blazing/logic/service/common"
"blazing/logic/service/fight"
"blazing/logic/service/fight/pvp"
@@ -37,6 +38,8 @@ func (h Controller) JoINtop(data *PetTOPLEVELnboundInfo, c *player.Player) (resu
Nick: c.Info.Nick,
FightMode: fightMode,
Status: status,
IsVip: cool.Config.ServerInfo.IsVip,
IsDebug: cool.Config.ServerInfo.IsDebug,
CatchTimes: pvp.AvailableCatchTimes(c.GetPetInfo(0)),
}
if callErr := Maincontroller.RPCClient.MatchJoinOrUpdate(joinPayload); callErr != nil {

View File

@@ -59,9 +59,15 @@ type session struct {
banPickDeadline time.Time
}
type queueKey struct {
FightMode uint32
IsVip uint32
IsDebug uint8
}
type manager struct {
mu sync.RWMutex
queues map[uint32][]pvpwire.QueuePlayerSnapshot
queues map[queueKey][]pvpwire.QueuePlayerSnapshot
lastSeen map[uint32]time.Time
localQueues map[uint32]*localQueueTicket
sessions map[string]*session
@@ -69,7 +75,7 @@ type manager struct {
}
var defaultManager = &manager{
queues: make(map[uint32][]pvpwire.QueuePlayerSnapshot),
queues: make(map[queueKey][]pvpwire.QueuePlayerSnapshot),
lastSeen: make(map[uint32]time.Time),
localQueues: make(map[uint32]*localQueueTicket),
sessions: make(map[string]*session),
@@ -222,6 +228,8 @@ func (m *manager) queueHeartbeatLoop(p *player.Player, ticket *localQueueTicket)
Nick: p.Info.Nick,
FightMode: ticket.fightMode,
Status: ticket.status,
IsVip: cool.Config.ServerInfo.IsVip,
IsDebug: cool.Config.ServerInfo.IsDebug,
JoinedAtUnix: time.Now().Unix(),
CatchTimes: filterAvailableCatchTimes(p.GetPetInfo(0)),
},
@@ -254,12 +262,13 @@ func (m *manager) handleQueueJoin(payload pvpwire.QueueJoinPayload) {
m.pruneExpiredQueueLocked(now)
playerInfo := payload.Player
m.lastSeen[playerInfo.UserID] = now
queue := m.queues[playerInfo.FightMode]
queueBucket := newQueueKey(playerInfo)
queue := m.queues[queueBucket]
for idx, queued := range queue {
if queued.UserID == playerInfo.UserID {
queue[idx] = playerInfo
m.queues[playerInfo.FightMode] = queue
m.queues[queueBucket] = queue
return
}
}
@@ -267,7 +276,7 @@ func (m *manager) handleQueueJoin(payload pvpwire.QueueJoinPayload) {
if len(queue) > 0 {
host := queue[0]
queue = queue[1:]
m.queues[playerInfo.FightMode] = queue
m.queues[queueBucket] = queue
delete(m.lastSeen, host.UserID)
delete(m.lastSeen, playerInfo.UserID)
@@ -286,7 +295,7 @@ func (m *manager) handleQueueJoin(payload pvpwire.QueueJoinPayload) {
return
}
m.queues[playerInfo.FightMode] = append(queue, playerInfo)
m.queues[queueBucket] = append(queue, playerInfo)
}
func (m *manager) handleQueueCancel(payload pvpwire.QueueCancelPayload) {
@@ -294,7 +303,7 @@ func (m *manager) handleQueueCancel(payload pvpwire.QueueCancelPayload) {
defer m.mu.Unlock()
delete(m.lastSeen, payload.UserID)
for mode, queue := range m.queues {
for key, queue := range m.queues {
next := make([]pvpwire.QueuePlayerSnapshot, 0, len(queue))
for _, queued := range queue {
if queued.UserID == payload.UserID {
@@ -302,7 +311,7 @@ func (m *manager) handleQueueCancel(payload pvpwire.QueueCancelPayload) {
}
next = append(next, queued)
}
m.queues[mode] = next
m.queues[key] = next
}
}
@@ -547,7 +556,7 @@ func (m *manager) closeSession(sessionID, reason string) {
}
func (m *manager) pruneExpiredQueueLocked(now time.Time) {
for mode, queue := range m.queues {
for key, queue := range m.queues {
next := make([]pvpwire.QueuePlayerSnapshot, 0, len(queue))
for _, queued := range queue {
last := m.lastSeen[queued.UserID]
@@ -557,7 +566,15 @@ func (m *manager) pruneExpiredQueueLocked(now time.Time) {
}
next = append(next, queued)
}
m.queues[mode] = next
m.queues[key] = next
}
}
func newQueueKey(player pvpwire.QueuePlayerSnapshot) queueKey {
return queueKey{
FightMode: player.FightMode,
IsVip: player.IsVip,
IsDebug: player.IsDebug,
}
}

View File

@@ -50,6 +50,8 @@ type QueuePlayerSnapshot struct {
Nick string `json:"nick"`
FightMode uint32 `json:"fightMode"`
Status uint32 `json:"status"`
IsVip uint32 `json:"isVip"`
IsDebug uint8 `json:"isDebug"`
JoinedAtUnix int64 `json:"joinedAtUnix"`
CatchTimes []uint32 `json:"catchTimes"`
}

View File

@@ -72,6 +72,19 @@ func (s *TowerService) Boss(towerLevel ...uint32) []model.BaseTowerConfig {
return config
}
func (s *TowerService) EnabledLevels() []uint32 {
var config []model.BaseTowerConfig
dbm_enable(s.Model).OrderAsc("tower_level").Cache(gdb.CacheOption{
Force: false,
}).Scan(&config)
levels := make([]uint32, 0, len(config))
for _, item := range config {
levels = append(levels, item.TowerLevel)
}
return levels
}
func NewTower1Service() *TowerService {
return NewTowerService(TowerType1)
}

View File

@@ -2,6 +2,7 @@ package service
import (
"blazing/cool"
configservice "blazing/modules/config/service"
"blazing/modules/player/model"
"errors"
"strings"
@@ -27,6 +28,19 @@ func (s *TaskService) ShopRequirementError() error {
return errors.New("请先完成试炼任务50")
}
var darkTask *model.Task
s.dbm(s.Model).Where("task_id", 110).Scan(&darkTask)
darkTaskBits := bitset32.New(0)
if darkTask != nil {
darkTaskBits = bitset32.From(darkTask.Data)
}
for _, level := range configservice.NewTower110Service().EnabledLevels() {
if !darkTaskBits.Test(uint(level)) {
return errors.New("请先完成暗黑门全部已开放关卡")
}
}
return nil
}