game

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Feb 26, 2022 License: BSD-3-Clause Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Unstarted means the lobby has been opened but never started.
	Unstarted gameState = "unstarted"
	// Ongoing means the lobby has already been started.
	Ongoing gameState = "ongoing"
	// GameOver means that the lobby had been start, but the max round limit
	// has already been reached.
	GameOver gameState = "gameOver"
)
View Source
const (
	DrawingBoardBaseWidth  = 1600
	DrawingBoardBaseHeight = 900
	MinBrushSize           = 8
	MaxBrushSize           = 32
)
View Source
const MaxPlayerNameLength int = 30

MaxPlayerNameLength defines how long a string can be at max when used as the playername.

Variables

View Source
var (
	LobbySettingBounds = &SettingBounds{
		MinDrawingTime:       60,
		MaxDrawingTime:       300,
		MinRounds:            1,
		MaxRounds:            20,
		MinMaxPlayers:        2,
		MaxMaxPlayers:        24,
		MinClientsPerIPLimit: 1,
		MaxClientsPerIPLimit: 24,
	}
	SupportedLanguages = map[string]string{
		"english_gb": "English (GB)",
		"english":    "English (US)",
		"italian":    "Italian",
		"german":     "German",
		"french":     "French",
		"dutch":      "Dutch",
	}
)

Functions

func CreateLobby

func CreateLobby(playerName, chosenLanguage string, publicLobby bool, drawingTime, rounds, maxPlayers, customWordsChance, clientsPerIPLimit int, customWords []string, enableVotekick bool) (*Player, *Lobby, error)

CreateLobby creates a new lobby including the initial player (owner) and optionally returns an error, if any occurred during creation.

func GetRandomWords

func GetRandomWords(wordCount int, lobby *Lobby) []string

GetRandomWords gets a custom amount of random words for the passed Lobby. The words will be chosen from the custom words and the default dictionary, depending on the settings specified by the lobbies creator.

func SanitizeName

func SanitizeName(name string) string

SanitizeName removes invalid characters from the players name, resolves emoji codes, limits the name length and generates a new name if necessary.

Types

type EditableLobbySettings

type EditableLobbySettings struct {
	// MaxPlayers defines the maximum amount of players in a single lobby.
	MaxPlayers int `json:"maxPlayers"`
	// CustomWords are additional words that will be used in addition to the
	// predefined words.
	// Public defines whether the lobby is being broadcast to clients asking
	// for available lobbies.
	Public bool `json:"public"`
	// EnableVotekick decides whether players are allowed to kick eachother
	// by casting majority votes.
	EnableVotekick bool `json:"enableVotekick"`
	// CustomWordsChance determines the chance of each word being a custom
	// word on the next word prompt. This needs to be an integer between
	// 0 and 100. The value represents a percentage.
	CustomWordsChance int `json:"customWordsChance"`
	// ClientsPerIPLimit helps preventing griefing by reducing each player
	// to one tab per IP address.
	ClientsPerIPLimit int `json:"clientsPerIpLimit"`
	// DrawingTime is the amount of seconds that each player has available to
	// finish their drawing.
	DrawingTime int `json:"drawingTime"`
	// Rounds defines how many iterations a lobby does before the game ends.
	// One iteration means every participant does one drawing.
	Rounds int `json:"rounds"`
}

EditableLobbySettings represents all lobby settings that are editable by the lobby owner after the lobby has already been opened.

type Fill

type Fill struct {
	X     float32  `json:"x"`
	Y     float32  `json:"y"`
	Color RGBColor `json:"color"`
}

Fill represents the usage of the fill bucket.

type FillEvent

type FillEvent struct {
	Type string `json:"type"`
	Data *Fill  `json:"data"`
}

FillEvent is basically the same as GameEvent, but with a specific Data type. We use this for reparsing as soon as we know that the type is right. It's a bit unperformant, but will do for now.

type GameEvent

type GameEvent struct {
	Type string      `json:"type"`
	Data interface{} `json:"data"`
}

GameEvent contains an eventtype and optionally any data.

type GameOverEvent

type GameOverEvent struct {
	*Ready
	PreviousWord string `json:"previousWord"`
}

GameOverEvent is basically the ready event, but contains the last word. This is required in order to show the last player the word, in case they didn't manage to guess it in time. This is necessary since the last word is usually part of the "next-turn" event, which we don't send, since the game is over already.

type KickVote

type KickVote struct {
	PlayerID          string `json:"playerId"`
	PlayerName        string `json:"playerName"`
	VoteCount         int    `json:"voteCount"`
	RequiredVoteCount int    `json:"requiredVoteCount"`
}

KickVote represents a players vote to kick another players. If the VoteCount is as great or greater than the RequiredVoteCount, the event indicates a successful kick vote. The voting is anonymous, meaning the voting player won't be exposed.

type Line

type Line struct {
	FromX     float32  `json:"fromX"`
	FromY     float32  `json:"fromY"`
	ToX       float32  `json:"toX"`
	ToY       float32  `json:"toY"`
	Color     RGBColor `json:"color"`
	LineWidth float32  `json:"lineWidth"`
}

Line is the struct that a client send when drawing

type LineEvent

type LineEvent struct {
	Type string `json:"type"`
	Data *Line  `json:"data"`
}

LineEvent is basically the same as GameEvent, but with a specific Data type. We use this for reparsing as soon as we know that the type is right. It's a bit unperformant, but will do for now.

type Lobby

type Lobby struct {
	// ID uniquely identified the Lobby.
	LobbyID string

	*EditableLobbySettings

	// DrawingTimeNew is the new value of the drawing time. If a round is
	// already ongoing, we can't simply change the drawing time, as it would
	// screw with the score calculation of the current turn.
	DrawingTimeNew int

	CustomWords []string

	// Whether the game has started, is ongoing or already over.
	State gameState

	// Owner references the Player that currently owns the lobby.
	// Meaning this player has rights to restart or change certain settings.
	Owner *Player

	// CurrentWord represents the word that was last selected. If no word has
	// been selected yet or the round is already over, this should be empty.
	CurrentWord string

	// Round is the round that the Lobby is currently in. This is a number
	// between 0 and Rounds. 0 indicates that it hasn't started yet.
	Round int

	Wordpack string
	// RoundEndTime represents the time at which the current round will end.
	// This is a UTC unix-timestamp in milliseconds.
	RoundEndTime int64

	//LastPlayerDisconnectTime is used to know since when a lobby is empty, in case
	//it is empty.
	LastPlayerDisconnectTime *time.Time

	WriteJSON func(player *Player, object interface{}) error
	// contains filtered or unexported fields
}

Lobby represents a game session. FIXME Field visibilities should be changed in case we ever serialize this.

func (*Lobby) AppendFill

func (lobby *Lobby) AppendFill(fill *FillEvent)

AppendFill adds a fill direction to the current drawing. This exists in order to prevent adding arbitrary elements to the drawing, as the backing array is an empty interface type.

func (*Lobby) AppendLine

func (lobby *Lobby) AppendLine(line *LineEvent)

AppendLine adds a line direction to the current drawing. This exists in order to prevent adding arbitrary elements to the drawing, as the backing array is an empty interface type.

func (*Lobby) CanIPConnect

func (lobby *Lobby) CanIPConnect(address string) bool

CanIPConnect checks whether the IP is still allowed regarding the lobbies clients per IP address limit. This function should only be called for players that aren't already in the lobby.

func (*Lobby) ClearDrawing

func (lobby *Lobby) ClearDrawing()

func (*Lobby) GetAvailableWordHints

func (lobby *Lobby) GetAvailableWordHints(player *Player) []*WordHint

GetAvailableWordHints returns a WordHint array depending on the players game state, since people that are drawing or have already guessed correctly can see all hints.

func (*Lobby) GetConnectedPlayerCount

func (lobby *Lobby) GetConnectedPlayerCount() int

GetConnectedPlayerCount returns the amount of player that have currently established a socket connection.

func (*Lobby) GetOccupiedPlayerSlots

func (lobby *Lobby) GetOccupiedPlayerSlots() int

GetOccupiedPlayerSlots counts the available slots which can be taken by new players. Whether a slot is available is determined by the player count and whether a player is disconnect or furthermore how long they have been disconnected for. Therefore the result of this function will differ from Lobby.GetConnectedPlayerCount.

func (*Lobby) GetPlayer

func (lobby *Lobby) GetPlayer(userSession string) *Player

GetPlayer searches for a player, identifying them by usersession.

func (*Lobby) GetPlayers

func (lobby *Lobby) GetPlayers() []*Player

func (*Lobby) HandleEvent

func (lobby *Lobby) HandleEvent(raw []byte, received *GameEvent, player *Player) error

func (*Lobby) HasConnectedPlayers

func (lobby *Lobby) HasConnectedPlayers() bool

func (*Lobby) HasFreePlayerSlot

func (lobby *Lobby) HasFreePlayerSlot() bool

HasFreePlayerSlot determines whether the lobby still has a slot for at least one more player. If a player has disconnected recently, the slot will be preserved for 5 minutes. This function should be used over Lobby.GetOccupiedPlayerSlots, as it is potentially faster.

func (*Lobby) IsPublic

func (lobby *Lobby) IsPublic() bool

func (*Lobby) JoinPlayer

func (lobby *Lobby) JoinPlayer(playerName string) *Player

JoinPlayer creates a new player object using the given name and adds it to the lobbies playerlist. The new players is returned.

func (*Lobby) OnPlayerConnectUnsynchronized

func (lobby *Lobby) OnPlayerConnectUnsynchronized(player *Player)

func (*Lobby) OnPlayerDisconnect

func (lobby *Lobby) OnPlayerDisconnect(player *Player)

func (*Lobby) Shutdown

func (lobby *Lobby) Shutdown()

Shutdown sends all players an event, indicating that the lobby will be shut down. The caller of this function should take care of not allowing new connections. Clients should gracefully disconnect.

func (*Lobby) Synchronized

func (lobby *Lobby) Synchronized(logic func())

Synchronized allows running a function while keeping the lobby locked via it's own mutex. This is useful in order to avoid having to relock a lobby multiple times, which might cause unexpected inconsistencies.

func (*Lobby) TriggerUpdateEvent

func (lobby *Lobby) TriggerUpdateEvent(eventType string, data interface{})

type Message

type Message struct {
	// Author is the player / thing that wrote the message
	Author string `json:"author"`
	// AuthorID is the unique identifier of the authors player object.
	AuthorID string `json:"authorId"`
	// Content is the actual message text.
	Content string `json:"content"`
}

Message represents a message in the chatroom.

type NameChangeEvent

type NameChangeEvent struct {
	PlayerID   string `json:"playerId"`
	PlayerName string `json:"playerName"`
}

type NextTurn

type NextTurn struct {
	Round        int       `json:"round"`
	Players      []*Player `json:"players"`
	RoundEndTime int       `json:"roundEndTime"`
	//PreviousWord signals the last chosen word. If empty, no word has been
	//chosen. The client can now themselves whether there has been a previous
	//turn, by looking at the current gamestate.
	PreviousWord string `json:"previousWord"`
}

NextTurn represents the data necessary for displaying the lobby state right after a new turn started. Meaning that no word has been chosen yet and therefore there are no wordhints and no current drawing instructions.

type OwnerChangeEvent

type OwnerChangeEvent struct {
	PlayerID   string `json:"playerId"`
	PlayerName string `json:"playerName"`
}

type Player

type Player struct {

	// ID uniquely identified the Player.
	ID string `json:"id"`
	// Name is the players displayed name
	Name string `json:"name"`
	// Score is the points that the player got in the current Lobby.
	Score int `json:"score"`
	// Connected defines whether the players websocket connection is currently
	// established. This has previously been in state but has been moved out
	// in order to avoid losing the state on refreshing the page.
	// While checking the websocket against nil would be enough, we still need
	// this field for sending it via the APIs.
	Connected bool `json:"connected"`
	// Rank is the current ranking of the player in his Lobby
	LastScore int         `json:"lastScore"`
	Rank      int         `json:"rank"`
	State     PlayerState `json:"state"`
	// contains filtered or unexported fields
}

Player represents a participant in a Lobby.

func (*Player) GetLastKnownAddress

func (player *Player) GetLastKnownAddress() string

GetLastKnownAddress returns the last known IP-Address used for an HTTP request.

func (*Player) GetUserSession

func (player *Player) GetUserSession() string

GetUserSession returns the players current user session.

func (*Player) GetWebsocket

func (player *Player) GetWebsocket() *websocket.Conn

GetWebsocket simply returns the players websocket connection. This method exists to encapsulate the websocket field and prevent accidental sending the websocket data via the network.

func (*Player) GetWebsocketMutex

func (player *Player) GetWebsocketMutex() *sync.Mutex

GetWebsocketMutex returns a mutex for locking the websocket connection. Since gorilla websockets shits it self when two calls happen at the same time, we need a mutex per player, since each player has their own socket. This getter extends to prevent accidentally sending the mutex via the network.

func (*Player) SetLastKnownAddress

func (player *Player) SetLastKnownAddress(address string)

SetLastKnownAddress sets the last known IP-Address used for an HTTP request. Can be retrieved via GetLastKnownAddress().

func (*Player) SetWebsocket

func (player *Player) SetWebsocket(socket *websocket.Conn)

SetWebsocket sets the given connection as the players websocket connection.

type PlayerState

type PlayerState string
const (
	Guessing PlayerState = "guessing"
	Drawing  PlayerState = "drawing"
	Standby  PlayerState = "standby"
)

type RGBColor

type RGBColor struct {
	R uint8 `json:"r"`
	G uint8 `json:"g"`
	B uint8 `json:"b"`
}

RGBColor represents a 24-bit color consisting of red, green and blue.

type Ready

type Ready struct {
	PlayerID     string `json:"playerId"`
	PlayerName   string `json:"playerName"`
	AllowDrawing bool   `json:"allowDrawing"`

	VotekickEnabled    bool          `json:"votekickEnabled"`
	GameState          gameState     `json:"gameState"`
	OwnerID            string        `json:"ownerId"`
	Round              int           `json:"round"`
	Rounds             int           `json:"rounds"`
	RoundEndTime       int           `json:"roundEndTime"`
	DrawingTimeSetting int           `json:"drawingTimeSetting"`
	WordHints          []*WordHint   `json:"wordHints"`
	Players            []*Player     `json:"players"`
	CurrentDrawing     []interface{} `json:"currentDrawing"`
}

Ready represents the initial state that a user needs upon connection. This includes all the necessary things for properly running a client without receiving any more data.

type SettingBounds

type SettingBounds struct {
	MinDrawingTime       int64 `json:"minDrawingTime"`
	MaxDrawingTime       int64 `json:"maxDrawingTime"`
	MinRounds            int64 `json:"minRounds"`
	MaxRounds            int64 `json:"maxRounds"`
	MinMaxPlayers        int64 `json:"minMaxPlayers"`
	MaxMaxPlayers        int64 `json:"maxMaxPlayers"`
	MinClientsPerIPLimit int64 `json:"minClientsPerIpLimit"`
	MaxClientsPerIPLimit int64 `json:"maxClientsPerIpLimit"`
}

SettingBounds defines the lower and upper bounds for the user-specified lobby creation input.

type WordHint

type WordHint struct {
	Character rune `json:"character"`
	Underline bool `json:"underline"`
}

WordHint describes a character of the word that is to be guessed, whether the character should be shown and whether it should be underlined on the UI.

Jump to

Keyboard shortcuts

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