You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
5.0 KiB
Go
219 lines
5.0 KiB
Go
package valueobjects
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/knowfoolery/backend/shared/errors"
|
|
"github.com/knowfoolery/backend/shared/types"
|
|
)
|
|
|
|
type LeaderboardEntry struct {
|
|
playerID types.UserID
|
|
playerName string
|
|
score int32
|
|
rank int32
|
|
achievedAt time.Time
|
|
sessionID types.GameSessionID
|
|
gamesPlayed int32
|
|
avgScore float32
|
|
lastActivity time.Time
|
|
metadata map[string]interface{}
|
|
}
|
|
|
|
func NewLeaderboardEntry(
|
|
playerID types.UserID,
|
|
playerName string,
|
|
score int32,
|
|
sessionID types.GameSessionID,
|
|
) (*LeaderboardEntry, error) {
|
|
if playerID == "" {
|
|
return nil, errors.ErrInvalidPlayerID
|
|
}
|
|
if playerName == "" {
|
|
return nil, errors.ErrInvalidPlayerName
|
|
}
|
|
if score < 0 {
|
|
return nil, errors.ErrInvalidScore
|
|
}
|
|
if sessionID == "" {
|
|
return nil, errors.ErrInvalidSessionID
|
|
}
|
|
|
|
now := time.Now()
|
|
return &LeaderboardEntry{
|
|
playerID: playerID,
|
|
playerName: playerName,
|
|
score: score,
|
|
rank: 0,
|
|
achievedAt: now,
|
|
sessionID: sessionID,
|
|
gamesPlayed: 1,
|
|
avgScore: float32(score),
|
|
lastActivity: now,
|
|
metadata: make(map[string]interface{}),
|
|
}, nil
|
|
}
|
|
|
|
func (le *LeaderboardEntry) PlayerID() types.UserID {
|
|
return le.playerID
|
|
}
|
|
|
|
func (le *LeaderboardEntry) PlayerName() string {
|
|
return le.playerName
|
|
}
|
|
|
|
func (le *LeaderboardEntry) Score() int32 {
|
|
return le.score
|
|
}
|
|
|
|
func (le *LeaderboardEntry) Rank() int32 {
|
|
return le.rank
|
|
}
|
|
|
|
func (le *LeaderboardEntry) AchievedAt() time.Time {
|
|
return le.achievedAt
|
|
}
|
|
|
|
func (le *LeaderboardEntry) SessionID() types.GameSessionID {
|
|
return le.sessionID
|
|
}
|
|
|
|
func (le *LeaderboardEntry) GamesPlayed() int32 {
|
|
return le.gamesPlayed
|
|
}
|
|
|
|
func (le *LeaderboardEntry) AvgScore() float32 {
|
|
return le.avgScore
|
|
}
|
|
|
|
func (le *LeaderboardEntry) LastActivity() time.Time {
|
|
return le.lastActivity
|
|
}
|
|
|
|
func (le *LeaderboardEntry) Metadata() map[string]interface{} {
|
|
result := make(map[string]interface{})
|
|
for k, v := range le.metadata {
|
|
result[k] = v
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (le *LeaderboardEntry) UpdateScore(newScore int32, sessionID types.GameSessionID) error {
|
|
if newScore < 0 {
|
|
return errors.ErrInvalidScore
|
|
}
|
|
if sessionID == "" {
|
|
return errors.ErrInvalidSessionID
|
|
}
|
|
|
|
if newScore > le.score {
|
|
le.score = newScore
|
|
le.sessionID = sessionID
|
|
le.achievedAt = time.Now()
|
|
}
|
|
|
|
le.gamesPlayed++
|
|
le.avgScore = (le.avgScore*float32(le.gamesPlayed-1) + float32(newScore)) / float32(le.gamesPlayed)
|
|
le.lastActivity = time.Now()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (le *LeaderboardEntry) SetRank(rank int32) error {
|
|
if rank <= 0 {
|
|
return errors.ErrInvalidRank
|
|
}
|
|
le.rank = rank
|
|
return nil
|
|
}
|
|
|
|
func (le *LeaderboardEntry) UpdatePlayerName(name string) error {
|
|
if name == "" {
|
|
return errors.ErrInvalidPlayerName
|
|
}
|
|
le.playerName = name
|
|
return nil
|
|
}
|
|
|
|
func (le *LeaderboardEntry) SetMetadata(key string, value interface{}) error {
|
|
if key == "" {
|
|
return errors.ErrInvalidMetadata
|
|
}
|
|
le.metadata[key] = value
|
|
return nil
|
|
}
|
|
|
|
func (le *LeaderboardEntry) RemoveMetadata(key string) {
|
|
delete(le.metadata, key)
|
|
}
|
|
|
|
func (le *LeaderboardEntry) IsEqual(other *LeaderboardEntry) bool {
|
|
if other == nil {
|
|
return false
|
|
}
|
|
return le.playerID == other.playerID &&
|
|
le.score == other.score &&
|
|
le.sessionID == other.sessionID
|
|
}
|
|
|
|
func (le *LeaderboardEntry) String() string {
|
|
return fmt.Sprintf("LeaderboardEntry{PlayerID: %s, Name: %s, Score: %d, Rank: %d}",
|
|
le.playerID, le.playerName, le.score, le.rank)
|
|
}
|
|
|
|
type LeaderboardEntrySnapshot struct {
|
|
PlayerID types.UserID `json:"player_id"`
|
|
PlayerName string `json:"player_name"`
|
|
Score int32 `json:"score"`
|
|
Rank int32 `json:"rank"`
|
|
AchievedAt time.Time `json:"achieved_at"`
|
|
SessionID types.GameSessionID `json:"session_id"`
|
|
GamesPlayed int32 `json:"games_played"`
|
|
AvgScore float32 `json:"avg_score"`
|
|
LastActivity time.Time `json:"last_activity"`
|
|
Metadata map[string]interface{} `json:"metadata"`
|
|
}
|
|
|
|
func (le *LeaderboardEntry) ToSnapshot() LeaderboardEntrySnapshot {
|
|
return LeaderboardEntrySnapshot{
|
|
PlayerID: le.playerID,
|
|
PlayerName: le.playerName,
|
|
Score: le.score,
|
|
Rank: le.rank,
|
|
AchievedAt: le.achievedAt,
|
|
SessionID: le.sessionID,
|
|
GamesPlayed: le.gamesPlayed,
|
|
AvgScore: le.avgScore,
|
|
LastActivity: le.lastActivity,
|
|
Metadata: le.Metadata(),
|
|
}
|
|
}
|
|
|
|
func (le *LeaderboardEntry) FromSnapshot(snapshot LeaderboardEntrySnapshot) error {
|
|
if snapshot.PlayerID == "" {
|
|
return errors.ErrInvalidPlayerID
|
|
}
|
|
if snapshot.PlayerName == "" {
|
|
return errors.ErrInvalidPlayerName
|
|
}
|
|
if snapshot.Score < 0 {
|
|
return errors.ErrInvalidScore
|
|
}
|
|
|
|
le.playerID = snapshot.PlayerID
|
|
le.playerName = snapshot.PlayerName
|
|
le.score = snapshot.Score
|
|
le.rank = snapshot.Rank
|
|
le.achievedAt = snapshot.AchievedAt
|
|
le.sessionID = snapshot.SessionID
|
|
le.gamesPlayed = snapshot.GamesPlayed
|
|
le.avgScore = snapshot.AvgScore
|
|
le.lastActivity = snapshot.LastActivity
|
|
le.metadata = make(map[string]interface{})
|
|
for k, v := range snapshot.Metadata {
|
|
le.metadata[k] = v
|
|
}
|
|
|
|
return nil
|
|
} |