entry

package
v0.0.12-entry Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2025 License: MIT Imports: 15 Imported by: 0

README

Entry Design

This repository contains the implementation of a matchmaking system designed to support different matching strategies and game modes. The project is organized into various components that facilitate the creation and management of player, group, team, and room entries using different matchmaking algorithms.

Directory Structure Demo

.
├── entry
│ ├── glicko2
│ │ ├── group.go
│ │ ├── player.go
│ │ ├── room.go
│ │ └── team.go
│ ├── goat_game
│ │ ├── group.go
│ │ ├── player.go
│ │ ├── room.go
│ │ └── team.go
│ ├── group.go
│ ├── player.go
│ ├── room.go
│ └── team.go
└── repository
  ├── group.go
  ├── player.go
  ├── room.go
  └── team.go

Components

the relastionship between entries

Root Directory

The entry root directory provides interfaces and base implementations for the four types of entries:

  • Interfaces:
    • Player
    • Group
    • Team
    • Room
  • Base Implementations:
    • PlayerBase
    • GroupBase
    • TeamBase
    • RoomBase

These interfaces define the core functionalities for different entities, while the bases provide foundational implementations that can be combinated.

Match Strategy (glicko2)

The glicko2 directory represents a specific match strategy based on the Glicko2 rating system. It includes implementations for the different types of entries, each combining the respective base class:

  • PlayerBaseGlicko2 (combines PlayerBase)
  • GroupBaseGlicko2 (combines GroupBase)
  • TeamBaseGlicko2 (combines TeamBase)
  • RoomBaseGlicko2 (combines RoomBase)
Game Mode (goat_game)

The goat_game directory represents a specific game mode. A game mode can support multiple match strategies. Here, it combines the Glicko2 strategy implementations to form its own entries:

  • goat_game.Player (combines PlayerBaseGlicko2, PlayerBaseGather)
  • goat_game.Group (combines GroupBaseGlicko2, GroupBaseGather)
  • goat_game.Team (combines TeamBaseGlicko2, TeamBaseGather)
  • goat_game.Room (combines RoomBaseGlicko2, RoomBaseGather)
Repository

In the repository directory, there are functions to create specific entry implementations based on provided parameters (game mode and match strategy). This allows for dynamic creation of entries like Player, Group, Team, and Room.

type PlayerMgr struct {
	*collection.Manager[string, entry.Player]
}

type GroupMgr struct {
	*collection.Manager[int64, entry.Group]
}

type TeamMgr struct {
	*collection.Manager[int64, entry.Team]
}

type RoomMgr struct {
	*collection.Manager[int64, entry.Room]
}

Factory Method

To use this matchmaking system, you can instantiate the desired base and strategy combinations using the factory method. Below is an example of how to create a player entry:

// repository/player.go
func (m *PlayerMgr) CreatePlayer(pInfo *pto.PlayerInfo) (p entry.Player, err error) {
	base := entry.NewPlayerBase(pInfo)

	switch base.GameMode {
	case constant.GameModeGoatGame:
		p, err = goat_game.CreatePlayer(base, pInfo)
	case constant.GameModeTest:
		p = base
	default:
		return nil, fmt.Errorf("unsupported game mode: %d", base.GameMode)
	}

	if err != nil {
		return nil, err
	}
	m.Add(p.UID(), p)
	return p, nil
}

// entry/goat_game/player.go
func CreatePlayer(base *entry.PlayerBase, pInfo *pto.PlayerInfo) entry.Player {
    p := &Player{}
    // ... other common fields

    p.withMatchStrategy(base, pInfo.Glicko2Info)
    return p
}

func (p *Player) withMatchStrategy(base *entry.PlayerBase, info *pto.Glicko2Info) {
    p.PlayerBaseGlicko2 = glicko2.CreatePlayerBase(base, info)
    // ... other match strategy initialization
}

Documentation

Index

Constants

View Source
const (
	InviteExpireSec = 60 * 5
)

Variables

This section is empty.

Functions

func Decode

func Decode(data []byte, v any) error

Decode decodes a byte array to current object

func Encode

func Encode(v any) ([]byte, error)

Encode encodes current object to a byte array with gob

func Json

func Json(v Jsoner) string

func PrintModes

func PrintModes()

func RegisterFactory

func RegisterFactory(gameMode constant.GameMode, factory Factory)

Types

type Coder

type Coder interface {
	// Encode encodes current object to a byte array
	Encode() ([]byte, error)
	// Decode decodes a byte array to current object
	Decode(data []byte) error
}

Coder is a interface for encoding and decoding data. It should be implemented by the specific game mode player, group, room, team, etc.

Note: Do not implement this interface for the common entries or strategy entries.

type Factory

type Factory interface {
	CreateRoom(mgr *Mgrs, base *RoomBase) (Room, error)
	CreatePlayer(mgr *Mgrs, base *PlayerBase, pInfo *pto.PlayerInfo) (Player, error)
	CreateTeam(mgr *Mgrs, base *TeamBase) (Team, error)
	CreateGroup(mgr *Mgrs, base *GroupBase) (Group, error)
}

func GetFactory

func GetFactory(gameMode constant.GameMode) Factory

type Group

type Group interface {
	Coder
	Jsoner

	// ID returns the unique group id.
	ID() int64

	// Base returns the base information of the group.
	// Here we define a concrete struct `GroupBase`
	// to hold the common fields to avoid lots getter and setter method.
	Base() *GroupBase

	// IsFull checks if the group is full.
	IsFull() bool

	// SetCaptain sets the captain of the group.
	SetCaptain(string)

	// GetCaptain returns the captain in the group.
	GetCaptain() string

	// CanPlayTogether checks if the player can play with the group's players.
	CanPlayTogether(*pto.PlayerInfo) error

	// GetPlayerInfos returns the player infos of the group.
	// This method usually used for sync group info to client.
	GetGroupInfo() *pto.GroupInfo

	// CanStartMatch checks if the group can start to match.
	// Maybe some game mode need to check if the group is full or not.
	// Maybe some game mode need all players to be ready.
	// If you have some special logics, please override this method.
	CanStartMatch() error

	// GetStartMatchTimeSec returns the start match time of the group.
	GetStartMatchTimeSec() int64

	// SetStartMatchTimeSec sets the start match time of the group.
	SetStartMatchTimeSec(sec int64)

	// Json returns the json string of the group.
	// You may need to lock when marshal it to avoid data race,
	// even if in print log.
	//
	// Note: it should be implemented by the specific game mode entry.
	// TODO: any other greater way?
	Json() string
}

Group represents a group of players.

type GroupBase

type GroupBase struct {
	// ReentrantLock is a reentrant L support multiple locks in the same goroutine.
	// Use it to help avoid deadlock.
	L *concurrent.ReentrantLock

	// GroupID is the unique id of the group.
	GroupID int64

	// IsAI indicates if the group is an AI group.
	IsAI bool

	// GameMode is the game mode of the group.
	GameMode constant.GameMode

	// ModeVersion is the version of the game mode of the group.
	// Only the same version of the players can be played together.
	ModeVersion int64

	// MatchStrategy is the current match strategy of the group.
	MatchStrategy constant.MatchStrategy

	// SupportMatchStrategies is the supported match strategies of the group.
	SupportMatchStrategies []constant.MatchStrategy

	// State is the current State of the group.
	State GroupState

	// Players holds the Players'ids in the group.
	Players []string

	// MatchID is a unique id to identify each match action.
	MatchID string

	// StartMatchTimeSec is the start match time of the group.
	StartMatchTimeSec int64

	// Roles holds the Roles of the players in the group.
	Roles map[string]GroupRole

	Configs GroupConfig

	// ReadyPlayer holds the unready players in the group.
	// In the project, we assume that the default does not
	// require all players to prepare to start matching,
	// so the map will be empty by default,
	// and you will need to re-initialize this field in the game mode that requires preparation
	UnReadyPlayer map[string]struct{}

	// InviteRecords holds the invite records of the group.
	// key: uid
	// value: expire time (s)
	InviteRecords map[string]int64

	// Settings holds the settings of the group.
	Settings GroupSettings
}

GroupBase holds the common fields of a Group for all kinds of game mode and match strategy.

func NewGroupBase

func NewGroupBase(
	groupID int64, playerLimit int, playerBase *PlayerBase,
) *GroupBase

NewGroupBase creates a new GroupBase.

func (*GroupBase) AddInviteRecord

func (g *GroupBase) AddInviteRecord(inviteeUID string, nowUnix int64)

func (*GroupBase) AddPlayer

func (g *GroupBase) AddPlayer(p Player) error

func (*GroupBase) AllowNearbyJoin

func (g *GroupBase) AllowNearbyJoin() bool

func (*GroupBase) AllowRecentJoin

func (g *GroupBase) AllowRecentJoin() bool

func (*GroupBase) Base

func (g *GroupBase) Base() *GroupBase

func (*GroupBase) CanPlayTogether

func (g *GroupBase) CanPlayTogether(info *pto.PlayerInfo) error

func (*GroupBase) CanStartMatch

func (g *GroupBase) CanStartMatch() error

func (*GroupBase) CheckState

func (g *GroupBase) CheckState(valids ...GroupState) error

func (*GroupBase) ClearPlayers

func (g *GroupBase) ClearPlayers()

func (*GroupBase) DelInviteRecord

func (g *GroupBase) DelInviteRecord(inviteeUID string)

func (*GroupBase) GetCaptain

func (g *GroupBase) GetCaptain() string

func (*GroupBase) GetGroupInfo

func (g *GroupBase) GetGroupInfo() *pto.GroupInfo

func (*GroupBase) GetInviteExpireTimeStamp

func (g *GroupBase) GetInviteExpireTimeStamp(uid string) int64

func (*GroupBase) GetInviteRecords

func (g *GroupBase) GetInviteRecords() map[string]int64

func (*GroupBase) GetPlayers

func (g *GroupBase) GetPlayers() []string

func (*GroupBase) GetStartMatchTimeSec

func (g *GroupBase) GetStartMatchTimeSec() int64

func (*GroupBase) GetState

func (g *GroupBase) GetState() GroupState

func (*GroupBase) GetStateWithLock

func (g *GroupBase) GetStateWithLock() GroupState

func (*GroupBase) ID

func (g *GroupBase) ID() int64

func (*GroupBase) IsFull

func (g *GroupBase) IsFull() bool

func (*GroupBase) IsInviteExpired

func (g *GroupBase) IsInviteExpired(uid string, nowUnix int64) bool

func (*GroupBase) IsMatchStrategySupported

func (g *GroupBase) IsMatchStrategySupported() bool

IsMatchStrategySupported checks if the group supports the current match strategy.

func (*GroupBase) Lock

func (g *GroupBase) Lock()

func (*GroupBase) PlayerExists

func (g *GroupBase) PlayerExists(uid string) bool

func (*GroupBase) PlayerLimit

func (g *GroupBase) PlayerLimit() int

func (*GroupBase) RemovePlayer

func (g *GroupBase) RemovePlayer(p Player) (empty bool)

func (*GroupBase) SetAllowNearbyJoin

func (g *GroupBase) SetAllowNearbyJoin(allow bool)

func (*GroupBase) SetAllowRecentJoin

func (g *GroupBase) SetAllowRecentJoin(allow bool)

func (*GroupBase) SetCaptain

func (g *GroupBase) SetCaptain(uid string)

func (*GroupBase) SetStartMatchTimeSec

func (g *GroupBase) SetStartMatchTimeSec(sec int64)

func (*GroupBase) SetState

func (g *GroupBase) SetState(s GroupState)

func (*GroupBase) SetStateWithLock

func (g *GroupBase) SetStateWithLock(s GroupState)

func (*GroupBase) UIDs

func (g *GroupBase) UIDs() []string

func (*GroupBase) Unlock

func (g *GroupBase) Unlock()

type GroupConfig

type GroupConfig struct {
	PlayerLimit     int
	InviteExpireSec int64
}

type GroupMgr

type GroupMgr struct {
	*collection.Manager[int64, Group]
	// contains filtered or unexported fields
}

func NewGroupMgr

func NewGroupMgr(groupIDStart int64) *GroupMgr

NewGroupMgr creates a group repository, `groupIDStart`: the starting group ID.

func (*GroupMgr) Encode

func (m *GroupMgr) Encode() map[constant.GameMode][][]byte

Encode encodes all groups into a map of game modes to their encoded bytes.

func (*GroupMgr) GenGroupID

func (m *GroupMgr) GenGroupID() int64

type GroupRole

type GroupRole int8
const (
	GroupRoleMember  GroupRole = 0
	GroupRoleCaptain GroupRole = 1
)

type GroupSettings

type GroupSettings struct {
	// NearbyJoinAllowed indicates whether nearby players can join the group.
	NearbyJoinAllowed bool

	// RecentJoinAllowed indicates whether recent players can join the group.
	RecentJoinAllowed bool
}

GroupSettings defines the settings of a group.

type GroupState

type GroupState int8
const (
	GroupStateInvite    GroupState = 0
	GroupStateMatch     GroupState = 1
	GroupStateGame      GroupState = 2
	GroupStateDissolved GroupState = 3
)

type Jsoner

type Jsoner interface {
	Lock()
	Unlock()
}

type Mgrs

type Mgrs struct {
	PlayerMgr *PlayerMgr
	GroupMgr  *GroupMgr
	TeamMgr   *TeamMgr
	RoomMgr   *RoomMgr
}

func (*Mgrs) CreateAITeam

func (m *Mgrs) CreateAITeam(g Group) (t Team, err error)

func (*Mgrs) CreateGroup

func (m *Mgrs) CreateGroup(playerLimit int, p Player) (g Group, err error)

func (*Mgrs) CreatePlayer

func (m *Mgrs) CreatePlayer(pInfo *pto.PlayerInfo) (p Player, err error)

func (*Mgrs) CreateRoom

func (m *Mgrs) CreateRoom(teamLimit int, t Team) (r Room, err error)

func (*Mgrs) CreateTeam

func (m *Mgrs) CreateTeam(g Group) (t Team, err error)

type Player

type Player interface {
	Coder
	Base() *PlayerBase
	UID() string
	GetPlayerInfo() *pto.PlayerInfo
	SetAttr(attr *pto.UploadPlayerAttr) error
}

Player represents a player in a Group.

type PlayerBase

type PlayerBase struct {
	// ReentrantLock is a reentrant L support multiple locks in the same goroutine
	// Use it to help avoid deadlock.
	L             *concurrent.ReentrantLock
	IsAI          bool
	GroupID       int64
	MatchStrategy constant.MatchStrategy

	OnlineState PlayerOnlineState
	VoiceState  PlayerVoiceState

	// TODO: other common attributes
	pto.PlayerInfo
	pto.Attribute
}

PlayerBase holds the common fields of a Player for all kinds of game mode and match strategy.

func NewPlayerBase

func NewPlayerBase(info *pto.PlayerInfo) *PlayerBase

func (*PlayerBase) Base

func (p *PlayerBase) Base() *PlayerBase

func (*PlayerBase) CheckOnlineState

func (p *PlayerBase) CheckOnlineState(valids ...PlayerOnlineState) error

CheckOnlineState checks if the player is in a valid online state.

func (*PlayerBase) GetMatchStrategy

func (p *PlayerBase) GetMatchStrategy() constant.MatchStrategy

func (*PlayerBase) GetMatchStrategyWithLock

func (p *PlayerBase) GetMatchStrategyWithLock() constant.MatchStrategy

func (*PlayerBase) GetOnlineState

func (p *PlayerBase) GetOnlineState() PlayerOnlineState

func (*PlayerBase) GetOnlineStateWithLock

func (p *PlayerBase) GetOnlineStateWithLock() PlayerOnlineState

func (*PlayerBase) GetPlayerInfo

func (p *PlayerBase) GetPlayerInfo() *pto.PlayerInfo

func (*PlayerBase) GetVoiceState

func (p *PlayerBase) GetVoiceState() PlayerVoiceState

func (*PlayerBase) Lock

func (p *PlayerBase) Lock()

func (*PlayerBase) SetAttr

func (p *PlayerBase) SetAttr(attr *pto.UploadPlayerAttr) error

func (*PlayerBase) SetMatchStrategy

func (p *PlayerBase) SetMatchStrategy(s constant.MatchStrategy)

func (*PlayerBase) SetMatchStrategyWithLock

func (p *PlayerBase) SetMatchStrategyWithLock(s constant.MatchStrategy)

func (*PlayerBase) SetOnlineState

func (p *PlayerBase) SetOnlineState(s PlayerOnlineState)

func (*PlayerBase) SetOnlineStateWithLock

func (p *PlayerBase) SetOnlineStateWithLock(s PlayerOnlineState)

func (*PlayerBase) SetVoiceState

func (p *PlayerBase) SetVoiceState(s PlayerVoiceState)

func (*PlayerBase) UID

func (p *PlayerBase) UID() string

func (*PlayerBase) Unlock

func (p *PlayerBase) Unlock()

type PlayerMgr

type PlayerMgr struct {
	*collection.Manager[string, Player]
}

func NewPlayerMgr

func NewPlayerMgr() *PlayerMgr

func (*PlayerMgr) Encode

func (m *PlayerMgr) Encode() map[constant.GameMode][][]byte

Encode encodes all players into a map of game modes to their encoded bytes.

type PlayerOnlineState

type PlayerOnlineState int8

PlayerOnlineState is the state of a player. TODO: try to use state machine to manage player state.

const (
	PlayerOnlineStateOffline  PlayerOnlineState = 0
	PlayerOnlineStateOnline   PlayerOnlineState = 1
	PlayerOnlineStateInGroup  PlayerOnlineState = 2
	PlayerOnlineStateInMatch  PlayerOnlineState = 3
	PlayerOnlineStateInGame   PlayerOnlineState = 4
	PlayerOnlineStateInSettle PlayerOnlineState = 5
)

type PlayerVoiceState

type PlayerVoiceState int8

PlayerVoiceState is the voice state of a player.

const (
	PlayerVoiceStateMute   PlayerVoiceState = 0
	PlayerVoiceStateUnmute PlayerVoiceState = 1
)

type Room

type Room interface {
	Coder
	Base() *RoomBase
	ID() int64
	NeedAI() bool
	GetMatchInfo() *pto.MatchInfo
}

type RoomBase

type RoomBase struct {
	RoomID    int64
	Teams     map[int64]struct{}
	TeamLimit int

	GameMode       constant.GameMode
	MatchStrategy  constant.MatchStrategy
	ModeVersion    int64
	FinishMatchSec int64

	EscapePlayer []string

	GameServerInfo pto.GameServerInfo
	// contains filtered or unexported fields
}

func NewRoomBase

func NewRoomBase(id int64, teamLimit int, t Team) *RoomBase

func (*RoomBase) AddEscapePlayer

func (r *RoomBase) AddEscapePlayer(uid string)

func (*RoomBase) AddTeam

func (r *RoomBase) AddTeam(t Team)

func (*RoomBase) Base

func (r *RoomBase) Base() *RoomBase

func (*RoomBase) GetEscapePlayers

func (r *RoomBase) GetEscapePlayers() []string

func (*RoomBase) GetMatchInfo

func (r *RoomBase) GetMatchInfo() *pto.MatchInfo

func (*RoomBase) GetTeams

func (r *RoomBase) GetTeams() []int64

func (*RoomBase) ID

func (r *RoomBase) ID() int64

func (*RoomBase) Lock

func (r *RoomBase) Lock()

func (*RoomBase) NeedAI

func (r *RoomBase) NeedAI() bool

func (*RoomBase) RLock

func (r *RoomBase) RLock()

func (*RoomBase) RUnlock

func (r *RoomBase) RUnlock()

func (*RoomBase) RemoveTeam

func (r *RoomBase) RemoveTeam(id int64)

func (*RoomBase) Unlock

func (r *RoomBase) Unlock()

type RoomMgr

type RoomMgr struct {
	*collection.Manager[int64, Room]
	// contains filtered or unexported fields
}

func NewRoomMgr

func NewRoomMgr(roomIDStart int64) *RoomMgr

NewRoomMgr creates a room repository.

func (*RoomMgr) Encode

func (m *RoomMgr) Encode() map[constant.GameMode][][]byte

Encode encodes all rooms into a map of game modes to room data.

type Team

type Team interface {
	Coder
	Base() *TeamBase
	ID() int64
}

type TeamBase

type TeamBase struct {
	UniqueID      int64 // UniqueID is the global unique team id.
	TeamID        int   // TeamID is the unique team id in one room, start from 1.
	IsAI          bool
	Groups        map[int64]struct{}
	GameMode      constant.GameMode
	MatchStrategy constant.MatchStrategy
	ModeVersion   int64
	// contains filtered or unexported fields
}

func NewTeamBase

func NewTeamBase(id int64, g Group) *TeamBase

func (*TeamBase) AddGroup

func (t *TeamBase) AddGroup(g Group)

func (*TeamBase) Base

func (t *TeamBase) Base() *TeamBase

func (*TeamBase) GetGroups

func (t *TeamBase) GetGroups() []int64

func (*TeamBase) ID

func (t *TeamBase) ID() int64

func (*TeamBase) Lock

func (t *TeamBase) Lock()

func (*TeamBase) RLock

func (t *TeamBase) RLock()

func (*TeamBase) RUnlock

func (t *TeamBase) RUnlock()

func (*TeamBase) RemoveGroup

func (t *TeamBase) RemoveGroup(id int64)

func (*TeamBase) Unlock

func (t *TeamBase) Unlock()

type TeamMgr

type TeamMgr struct {
	*collection.Manager[int64, Team]
	// contains filtered or unexported fields
}

func NewTeamMgr

func NewTeamMgr(teamIDStart int64) *TeamMgr

NewTeamMgr creates a team repository.

func (*TeamMgr) Encode

func (m *TeamMgr) Encode() map[constant.GameMode][][]byte

Encode encodes all teams into a map of game modes to their encoded bytes.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL