2025-08-09 00:05:06 -05:00

500 lines
12 KiB
Go

/*
Package users is the active record implementation for user accounts in the game.
The users package provides comprehensive user management for the game, including authentication, character progression, inventory, equipment, and game state management. It handles all aspects of player accounts from registration to advanced gameplay features.
# Basic Usage
To retrieve a user by ID:
user, err := users.Find(db, 1)
if err != nil {
log.Fatal(err)
}
fmt.Printf("User: %s (Level %d)\n", user.Username, user.Level)
To find a user by username:
user, err := users.ByUsername(db, "playerName")
if err != nil {
log.Fatal(err)
}
To find a user by email:
user, err := users.ByEmail(db, "player@example.com")
if err != nil {
log.Fatal(err)
}
# Creating Users with Builder Pattern
The package provides a comprehensive builder for creating new user accounts:
## Basic User Creation
user, err := users.NewBuilder(db).
WithUsername("newplayer").
WithPassword("hashedPassword").
WithEmail("newplayer@example.com").
WithClassID(1).
Create()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created user with ID: %d\n", user.ID)
## Advanced User Creation
user, err := users.NewBuilder(db).
WithUsername("hero").
WithPassword("secureHash").
WithEmail("hero@example.com").
WithVerified(true).
WithClassID(2).
WithPosition(100, -50).
WithLevel(5).
WithGold(500).
WithStats(8, 7, 10, 9). // strength, dex, attack, defense
WithHP(30, 30).
WithMP(20, 20).
WithSpells([]string{"1", "3", "5"}).
WithTowns([]string{"1", "2"}).
AsAdmin().
Create()
The builder automatically sets sensible defaults for all fields if not specified.
# User Management
## Authentication and Verification
user, _ := users.Find(db, userID)
// Check verification status
if user.IsVerified() {
fmt.Println("User email is verified")
}
// Check authorization levels
if user.IsAdmin() {
fmt.Println("User has admin privileges")
}
if user.IsModerator() {
fmt.Println("User has moderator privileges")
}
## Activity Tracking
// Update last online time
user.UpdateLastOnline()
user.Save()
// Get activity information
registered := user.RegisteredTime()
lastOnline := user.LastOnlineTime()
fmt.Printf("Registered: %s\n", registered.Format("Jan 2, 2006"))
fmt.Printf("Last online: %s\n", lastOnline.Format("Jan 2 15:04"))
# Character Management
## Stats and Progression
user, _ := users.Find(db, userID)
// Get character stats
stats := user.GetStats()
fmt.Printf("Level %d: HP %d/%d, MP %d/%d\n",
stats["level"], stats["hp"], stats["max_hp"],
stats["mp"], stats["max_mp"])
// Update character progression
user.Level = 10
user.Exp = 5000
user.MaxHP = 50
user.HP = 50
user.Save()
## Position and Movement
// Get current position
x, y := user.GetPosition()
fmt.Printf("Player at (%d, %d)\n", x, y)
// Move player
user.SetPosition(newX, newY)
user.Currently = "Exploring the forest"
user.Save()
## Combat Status
if user.IsFighting() {
fmt.Printf("Fighting monster ID %d (HP: %d)\n",
user.MonsterID, user.MonsterHP)
}
if user.IsAlive() {
fmt.Printf("Player has %d HP remaining\n", user.HP)
}
# Spell System
## Spell Management
user, _ := users.Find(db, userID)
// Get known spells
spells := user.GetSpellIDs()
fmt.Printf("Player knows %d spells: %v\n", len(spells), spells)
// Check if player knows a specific spell
if user.HasSpell("5") {
fmt.Println("Player knows spell 5")
}
// Learn new spells
newSpells := append(spells, "7", "8")
user.SetSpellIDs(newSpells)
user.Save()
## Spell Integration
func castSpell(db *database.DB, userID int, spellID string) error {
user, err := users.Find(db, userID)
if err != nil {
return err
}
if !user.HasSpell(spellID) {
return fmt.Errorf("user doesn't know spell %s", spellID)
}
// Spell casting logic here...
return nil
}
# Town and Travel System
## Town Visits
user, _ := users.Find(db, userID)
// Get visited towns
towns := user.GetTownIDs()
fmt.Printf("Visited %d towns: %v\n", len(towns), towns)
// Check if player has visited a town
if user.HasVisitedTown("3") {
fmt.Println("Player has been to town 3")
}
// Visit new town
visitedTowns := append(towns, "4")
user.SetTownIDs(visitedTowns)
user.Save()
## Travel Integration
func visitTown(db *database.DB, userID int, townID string) error {
user, err := users.Find(db, userID)
if err != nil {
return err
}
// Add town to visited list if not already there
if !user.HasVisitedTown(townID) {
towns := user.GetTownIDs()
user.SetTownIDs(append(towns, townID))
}
// Update position and status
// town coordinates would be looked up here
user.Currently = fmt.Sprintf("In town %s", townID)
return user.Save()
}
# Equipment System
## Equipment Management
user, _ := users.Find(db, userID)
// Get all equipment
equipment := user.GetEquipment()
weapon := equipment["weapon"].(map[string]interface{})
armor := equipment["armor"].(map[string]interface{})
fmt.Printf("Weapon: %s (ID: %d)\n", weapon["name"], weapon["id"])
fmt.Printf("Armor: %s (ID: %d)\n", armor["name"], armor["id"])
// Equip new items
user.WeaponID = 15
user.WeaponName = "Dragon Sword"
user.ArmorID = 8
user.ArmorName = "Steel Plate"
user.Save()
# Query Operations
## Level-Based Queries
// Get all players at a specific level
level5Players, err := users.ByLevel(db, 5)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Level 5 players (%d):\n", len(level5Players))
for _, player := range level5Players {
fmt.Printf("- %s (EXP: %d)\n", player.Username, player.Exp)
}
## Online Status Queries
// Get players online in the last hour
onlinePlayers, err := users.Online(db, time.Hour)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Players online in last hour (%d):\n", len(onlinePlayers))
for _, player := range onlinePlayers {
lastSeen := time.Since(player.LastOnlineTime())
fmt.Printf("- %s (last seen %v ago)\n", player.Username, lastSeen)
}
# Database Schema
The users table contains extensive character and game state information:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
email TEXT NOT NULL,
verified INTEGER NOT NULL DEFAULT 0,
token TEXT NOT NULL DEFAULT '',
registered INTEGER NOT NULL DEFAULT (unixepoch()),
last_online INTEGER NOT NULL DEFAULT (unixepoch()),
auth INTEGER NOT NULL DEFAULT 0,
x INTEGER NOT NULL DEFAULT 0,
y INTEGER NOT NULL DEFAULT 0,
class_id INTEGER NOT NULL DEFAULT 0,
currently TEXT NOT NULL DEFAULT 'In Town',
fighting INTEGER NOT NULL DEFAULT 0,
-- Combat state fields
monster_id INTEGER NOT NULL DEFAULT 0,
monster_hp INTEGER NOT NULL DEFAULT 0,
monster_sleep INTEGER NOT NULL DEFAULT 0,
monster_immune INTEGER NOT NULL DEFAULT 0,
uber_damage INTEGER NOT NULL DEFAULT 0,
uber_defense INTEGER NOT NULL DEFAULT 0,
-- Character stats
hp INTEGER NOT NULL DEFAULT 15,
mp INTEGER NOT NULL DEFAULT 0,
tp INTEGER NOT NULL DEFAULT 10,
max_hp INTEGER NOT NULL DEFAULT 15,
max_mp INTEGER NOT NULL DEFAULT 0,
max_tp INTEGER NOT NULL DEFAULT 10,
level INTEGER NOT NULL DEFAULT 1,
gold INTEGER NOT NULL DEFAULT 100,
exp INTEGER NOT NULL DEFAULT 0,
gold_bonus INTEGER NOT NULL DEFAULT 0,
exp_bonus INTEGER NOT NULL DEFAULT 0,
strength INTEGER NOT NULL DEFAULT 5,
dexterity INTEGER NOT NULL DEFAULT 5,
attack INTEGER NOT NULL DEFAULT 5,
defense INTEGER NOT NULL DEFAULT 5,
-- Equipment
weapon_id INTEGER NOT NULL DEFAULT 0,
armor_id INTEGER NOT NULL DEFAULT 0,
shield_id INTEGER NOT NULL DEFAULT 0,
slot_1_id INTEGER NOT NULL DEFAULT 0,
slot_2_id INTEGER NOT NULL DEFAULT 0,
slot_3_id INTEGER NOT NULL DEFAULT 0,
weapon_name TEXT NOT NULL DEFAULT '',
armor_name TEXT NOT NULL DEFAULT '',
shield_name TEXT NOT NULL DEFAULT '',
slot_1_name TEXT NOT NULL DEFAULT '',
slot_2_name TEXT NOT NULL DEFAULT '',
slot_3_name TEXT NOT NULL DEFAULT '',
-- Game state
drop_code INTEGER NOT NULL DEFAULT 0,
spells TEXT NOT NULL DEFAULT '',
towns TEXT NOT NULL DEFAULT ''
)
# Advanced Features
## Character Progression
func levelUpCharacter(user *users.User, newLevel int) {
user.Level = newLevel
// Increase base stats
user.MaxHP += 5
user.HP = user.MaxHP // Full heal on level up
user.MaxMP += 2
user.MP = user.MaxMP
// Stat bonuses
user.Strength++
user.Attack++
user.Defense++
user.Save()
}
## Combat Integration
func startCombat(user *users.User, monsterID int) error {
if user.IsFighting() {
return fmt.Errorf("already in combat")
}
user.Fighting = 1
user.MonsterID = monsterID
// monster HP would be looked up from monsters table
user.MonsterHP = 50
user.Currently = "Fighting"
return user.Save()
}
func endCombat(user *users.User, won bool) error {
user.Fighting = 0
user.MonsterID = 0
user.MonsterHP = 0
user.MonsterSleep = 0
user.MonsterImmune = 0
if won {
user.Currently = "Victorious"
// Award experience and gold
} else {
user.Currently = "Defeated"
user.HP = 0 // Player defeated
}
return user.Save()
}
## Administrative Functions
func promoteUser(db *database.DB, username string, authLevel int) error {
user, err := users.ByUsername(db, username)
if err != nil {
return err
}
user.Auth = authLevel
return user.Save()
}
func getUsersByAuthLevel(db *database.DB, minAuth int) ([]*users.User, error) {
allUsers, err := users.All(db)
if err != nil {
return nil, err
}
var authorizedUsers []*users.User
for _, user := range allUsers {
if user.Auth >= minAuth {
authorizedUsers = append(authorizedUsers, user)
}
}
return authorizedUsers, nil
}
# Performance Considerations
The users table is large and frequently accessed. Consider:
## Efficient Queries
// Use specific lookups when possible
user, _ := users.ByUsername(db, username) // Uses index
user, _ := users.ByEmail(db, email) // Uses index
// Limit results for admin interfaces
onlineUsers, _ := users.Online(db, time.Hour) // Bounded by time
levelUsers, _ := users.ByLevel(db, targetLevel) // Bounded by level
## Caching Strategies
// Cache frequently accessed user data
type UserCache struct {
users map[int]*users.User
mutex sync.RWMutex
}
func (c *UserCache) GetUser(db *database.DB, id int) (*users.User, error) {
c.mutex.RLock()
if user, ok := c.users[id]; ok {
c.mutex.RUnlock()
return user, nil
}
c.mutex.RUnlock()
user, err := users.Find(db, id)
if err != nil {
return nil, err
}
c.mutex.Lock()
c.users[id] = user
c.mutex.Unlock()
return user, nil
}
# Integration Examples
## Session Management
func authenticateUser(db *database.DB, username, password string) (*users.User, error) {
user, err := users.ByUsername(db, username)
if err != nil {
return nil, fmt.Errorf("user not found")
}
if !user.IsVerified() {
return nil, fmt.Errorf("email not verified")
}
// Verify password (implement password checking)
if !verifyPassword(user.Password, password) {
return nil, fmt.Errorf("invalid password")
}
// Update last online
user.UpdateLastOnline()
user.Save()
return user, nil
}
## Game State Management
func saveGameState(user *users.User, gameData GameState) error {
user.X = gameData.X
user.Y = gameData.Y
user.HP = gameData.HP
user.MP = gameData.MP
user.Currently = gameData.Status
if gameData.InCombat {
user.Fighting = 1
user.MonsterID = gameData.MonsterID
user.MonsterHP = gameData.MonsterHP
}
return user.Save()
}
The users package provides comprehensive player account management with support for all game mechanics including character progression, combat, equipment, spells, and world exploration.
*/
package users