first
This commit is contained in:
+310
@@ -0,0 +1,310 @@
|
||||
package room
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Player struct {
|
||||
ID string
|
||||
Nickname string
|
||||
IsReady bool
|
||||
IsHost bool
|
||||
IsBot bool
|
||||
Send chan []byte
|
||||
}
|
||||
|
||||
type Room struct {
|
||||
ID string
|
||||
State string
|
||||
MaxPlayers int
|
||||
HarmonyTarget int
|
||||
ChaosMode bool
|
||||
Players map[string]*Player
|
||||
PlayerOrder []string
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
rooms map[string]*Room
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewManager() *Manager {
|
||||
return &Manager{
|
||||
rooms: make(map[string]*Room),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) CreateTestRoom(roomID string, playerCount int) *Room {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
rm := &Room{
|
||||
ID: roomID,
|
||||
State: "waiting",
|
||||
MaxPlayers: playerCount,
|
||||
Players: make(map[string]*Player),
|
||||
}
|
||||
|
||||
botNames := []string{"Bot-A", "Bot-B", "Bot-C", "Bot-D", "Bot-E"}
|
||||
for i := 0; i < playerCount-1; i++ {
|
||||
botID := fmt.Sprintf("bot_%s_%d", roomID, i)
|
||||
bot := &Player{
|
||||
ID: botID,
|
||||
Nickname: botNames[i%len(botNames)],
|
||||
IsReady: true,
|
||||
IsBot: true,
|
||||
Send: nil,
|
||||
}
|
||||
rm.Players[botID] = bot
|
||||
rm.PlayerOrder = append(rm.PlayerOrder, botID)
|
||||
}
|
||||
|
||||
m.rooms[roomID] = rm
|
||||
return rm
|
||||
}
|
||||
|
||||
func (m *Manager) CreateRoom(hostID, nickname string, maxPlayers int) *Room {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
roomID := generateRoomID()
|
||||
room := &Room{
|
||||
ID: roomID,
|
||||
State: "waiting",
|
||||
MaxPlayers: maxPlayers,
|
||||
Players: make(map[string]*Player),
|
||||
}
|
||||
|
||||
host := &Player{
|
||||
ID: hostID,
|
||||
Nickname: nickname,
|
||||
IsHost: true,
|
||||
Send: make(chan []byte, 256),
|
||||
}
|
||||
room.Players[hostID] = host
|
||||
room.PlayerOrder = append(room.PlayerOrder, hostID)
|
||||
|
||||
m.rooms[roomID] = room
|
||||
return room
|
||||
}
|
||||
|
||||
func (m *Manager) GetRoom(roomID string) *Room {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
return m.rooms[roomID]
|
||||
}
|
||||
|
||||
func (m *Manager) ListRooms() []map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
var list []map[string]interface{}
|
||||
for _, rm := range m.rooms {
|
||||
rm.mu.RLock()
|
||||
realCount := 0
|
||||
totalCount := len(rm.Players)
|
||||
for _, p := range rm.Players {
|
||||
if !p.IsBot {
|
||||
realCount++
|
||||
}
|
||||
}
|
||||
rm.mu.RUnlock()
|
||||
list = append(list, map[string]interface{}{
|
||||
"room_id": rm.ID,
|
||||
"state": rm.State,
|
||||
"player_count": totalCount,
|
||||
"real_players": realCount,
|
||||
"max_players": rm.MaxPlayers,
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (m *Manager) JoinRoom(roomID, playerID, nickname string) (*Room, bool) {
|
||||
m.mu.RLock()
|
||||
room, exists := m.rooms[roomID]
|
||||
m.mu.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
room.mu.Lock()
|
||||
defer room.mu.Unlock()
|
||||
|
||||
if len(room.Players) >= room.MaxPlayers {
|
||||
return nil, false
|
||||
}
|
||||
if room.State != "waiting" {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
player := &Player{
|
||||
ID: playerID,
|
||||
Nickname: nickname,
|
||||
Send: make(chan []byte, 256),
|
||||
}
|
||||
room.Players[playerID] = player
|
||||
room.PlayerOrder = append(room.PlayerOrder, playerID)
|
||||
|
||||
hasRealHost := false
|
||||
for _, p := range room.Players {
|
||||
if p.IsHost && !p.IsBot {
|
||||
hasRealHost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasRealHost {
|
||||
for _, p := range room.Players {
|
||||
p.IsHost = false
|
||||
}
|
||||
player.IsHost = true
|
||||
}
|
||||
|
||||
return room, true
|
||||
}
|
||||
|
||||
func (m *Manager) LeaveRoom(roomID, playerID string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
room, exists := m.rooms[roomID]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
room.mu.Lock()
|
||||
defer room.mu.Unlock()
|
||||
|
||||
delete(room.Players, playerID)
|
||||
|
||||
newOrder := make([]string, 0)
|
||||
for _, id := range room.PlayerOrder {
|
||||
if id != playerID {
|
||||
newOrder = append(newOrder, id)
|
||||
}
|
||||
}
|
||||
room.PlayerOrder = newOrder
|
||||
|
||||
realCount := 0
|
||||
for _, p := range room.Players {
|
||||
if !p.IsBot {
|
||||
realCount++
|
||||
}
|
||||
}
|
||||
if realCount == 0 && !isTestRoom(roomID) {
|
||||
delete(m.rooms, roomID)
|
||||
return
|
||||
}
|
||||
|
||||
if realCount == 0 && isTestRoom(roomID) {
|
||||
for _, p := range room.Players {
|
||||
p.IsHost = false
|
||||
}
|
||||
room.State = "waiting"
|
||||
return
|
||||
}
|
||||
|
||||
hasHost := false
|
||||
for _, p := range room.Players {
|
||||
if p.IsHost && !p.IsBot {
|
||||
hasHost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasHost {
|
||||
for _, p := range room.Players {
|
||||
p.IsHost = false
|
||||
}
|
||||
for _, id := range room.PlayerOrder {
|
||||
p := room.Players[id]
|
||||
if !p.IsBot {
|
||||
p.IsHost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isTestRoom(roomID string) bool {
|
||||
return roomID == "TEST3" || roomID == "TEST4" || roomID == "TEST5" || roomID == "TEST6"
|
||||
}
|
||||
|
||||
func (m *Manager) SetReady(roomID, playerID string, ready bool) bool {
|
||||
room := m.GetRoom(roomID)
|
||||
if room == nil {
|
||||
return false
|
||||
}
|
||||
room.mu.Lock()
|
||||
defer room.mu.Unlock()
|
||||
p, exists := room.Players[playerID]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
p.IsReady = ready
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *Room) GetPlayerInfos() []map[string]interface{} {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
var infos []map[string]interface{}
|
||||
for _, id := range r.PlayerOrder {
|
||||
p, ok := r.Players[id]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
infos = append(infos, map[string]interface{}{
|
||||
"player_id": p.ID,
|
||||
"nickname": p.Nickname,
|
||||
"is_ready": p.IsReady,
|
||||
"is_host": p.IsHost,
|
||||
"is_bot": p.IsBot,
|
||||
})
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
func (r *Room) BroadcastToReal(data []byte) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
for _, p := range r.Players {
|
||||
if p.IsBot || p.Send == nil {
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case p.Send <- data:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Room) SendToPlayer(playerID string, data []byte) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
p, ok := r.Players[playerID]
|
||||
if !ok || p.IsBot || p.Send == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case p.Send <- data:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func generateRoomID() string {
|
||||
src := rand.NewSource(time.Now().UnixNano())
|
||||
r := rand.New(src)
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
b := make([]byte, 6)
|
||||
for i := range b {
|
||||
b[i] = charset[r.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
Reference in New Issue
Block a user