eq2go/internal/housing/README.md

7.8 KiB

Housing Package

The housing package provides a complete housing system for EverQuest II servers, allowing players to purchase, manage, and customize their in-game homes.

Overview

This package implements a streamlined housing system with three core components:

  • House: Represents purchasable house types/zones with costs and requirements
  • CharacterHouse: Represents houses owned by specific characters
  • HousingManager: Orchestrates all housing operations including purchases, upkeep, and packet communication

Features

House Management

  • Multiple house types with different costs, requirements, and features
  • Alignment and guild level restrictions
  • Vault storage slots and exit coordinates
  • Configurable costs in coins and status points

Character Houses

  • Individual house ownership tracking
  • Upkeep payment system with automatic processing
  • House settings (name, visit permissions, notes)
  • Access control lists for other players
  • Item placement and management
  • Transaction history tracking

System Features

  • Automatic upkeep processing with configurable grace periods
  • Foreclosure system for unpaid upkeep
  • Maximum house limits per player
  • Integrated packet building for client communication
  • Database persistence with MySQL support
  • Comprehensive logging and error handling

Usage

Basic Setup

import "eq2emu/internal/housing"

// Create housing manager
logger := &MyLogger{} // Implement housing.Logger interface
config := housing.HousingConfig{
    EnableUpkeep:       true,
    EnableForeclosure:  true,
    UpkeepGracePeriod:  7 * 24 * 3600, // 7 days in seconds
    MaxHousesPerPlayer: 10,
    EnableStatistics:   true,
}

hm := housing.NewHousingManager(db, logger, config)

// Initialize and load house data
ctx := context.Background()
if err := hm.Initialize(ctx); err != nil {
    log.Fatal("Failed to initialize housing:", err)
}

House Purchase Flow

// Player wants to purchase house type 1
playerManager := &MyPlayerManager{} // Implement housing.PlayerManager interface
characterID := int32(12345)
houseTypeID := int32(1)

house, err := hm.PurchaseHouse(ctx, characterID, houseTypeID, playerManager)
if err != nil {
    // Handle purchase error (insufficient funds, requirements not met, etc.)
    return err
}

// House purchased successfully
fmt.Printf("Player %d purchased house %s", characterID, house.Settings.HouseName)

Upkeep Management

// Pay upkeep for a specific house
houseUniqueID := int64(98765)
err := hm.PayUpkeep(ctx, houseUniqueID, playerManager)
if err != nil {
    // Handle upkeep payment error
    return err
}

// Automatic upkeep processing runs in background
// No manual intervention needed

Packet Communication

// Send house purchase UI to client
house, exists := hm.GetHouse(houseTypeID)
if exists {
    err := hm.SendHousePurchasePacket(characterID, clientVersion, house)
    // Packet sent to client
}

// Send player's house list to client
err := hm.SendCharacterHousesPacket(characterID, clientVersion)
// Housing list packet sent to client

Architecture

Core Types

  • House: Static house type definitions loaded from database
  • CharacterHouse: Player-owned house instances with settings and history
  • HousingManager: Central coordinator for all housing operations

Database Integration

The housing system integrates with MySQL databases using the centralized database package:

-- House type definitions
character_house_zones (id, name, cost_coins, cost_status, ...)

-- Player house instances  
character_houses (unique_id, char_id, house_id, upkeep_due, ...)

Packet Integration

Integrates with the centralized packet system using XML-driven packet definitions:

  • Uses packets.GetPacket() to load packet definitions
  • Builds packets with packets.NewPacketBuilder()
  • Supports multiple client versions automatically

Configuration

HousingConfig Options

  • EnableUpkeep: Enable automatic upkeep processing
  • EnableForeclosure: Allow foreclosure of houses with overdue upkeep
  • UpkeepGracePeriod: Grace period in seconds before foreclosure
  • MaxHousesPerPlayer: Maximum houses per character
  • EnableStatistics: Enable housing statistics tracking

House Types

House types are configured in the database with these properties:

  • Cost: Coin and status point requirements
  • Upkeep: Weekly maintenance costs
  • Alignment: Good/Evil/Neutral/Any restrictions
  • Guild Level: Minimum guild level required
  • Vault Slots: Number of storage slots provided
  • Zone Info: Location and exit coordinates

Constants

The package provides extensive constants for:

  • House Types: Cottage, Mansion, Keep, etc.
  • Access Levels: Owner, Friend, Visitor, Guild Member
  • Transaction Types: Purchase, Upkeep, Deposit, etc.
  • Permission Flags: Enter, Place Items, Vault Access, etc.
  • Status Codes: Active, Upkeep Due, Foreclosed, etc.

See constants.go for complete listings and default values.

Interfaces

Logger Interface

Implement this interface to provide logging:

type Logger interface {
    LogInfo(system, format string, args ...interface{})
    LogError(system, format string, args ...interface{}) 
    LogDebug(system, format string, args ...interface{})
    LogWarning(system, format string, args ...interface{})
}

PlayerManager Interface

Implement this interface to integrate with player systems:

type PlayerManager interface {
    CanPlayerAffordHouse(characterID int32, coinCost, statusCost int64) (bool, error)
    DeductPlayerCoins(characterID int32, amount int64) error
    DeductPlayerStatus(characterID int32, amount int64) error
    GetPlayerAlignment(characterID int32) (int8, error)
    GetPlayerGuildLevel(characterID int32) (int8, error)
}

Utility Functions

Currency Formatting

housing.FormatCurrency(15250) // Returns "1g 52s 50c"
housing.FormatCurrency(1000)  // Returns "10s" 
housing.FormatCurrency(50)    // Returns "50c"

Upkeep Date Formatting

housing.FormatUpkeepDue(time.Now().Add(24 * time.Hour)) // "Due in 1 days"
housing.FormatUpkeepDue(time.Now().Add(-24 * time.Hour)) // "Overdue (1 days)"

Testing

The package includes comprehensive tests with mock implementations:

go test ./internal/housing/ -v

Tests cover:

  • House and CharacterHouse creation
  • Purchase validation (funds, alignment, guild level)
  • Upkeep processing and foreclosure
  • Packet building integration
  • Currency and date formatting
  • Full system integration scenarios

Error Handling

The housing system provides detailed error codes and messages:

  • HouseErrorInsufficientFunds: Player cannot afford purchase/upkeep
  • HouseErrorAlignmentRestriction: Player alignment doesn't meet requirements
  • HouseErrorGuildLevelRestriction: Player guild level too low
  • HouseErrorMaxHousesReached: Player at house limit
  • HouseErrorHouseNotFound: Invalid house type requested

See constants.go for complete error code definitions.

Performance

The housing system is designed for efficiency:

  • In-Memory Caching: House types and character houses cached in memory
  • Lazy Loading: Character houses loaded on first access
  • Background Processing: Upkeep processing runs asynchronously
  • Optimized Queries: Direct SQL queries without ORM overhead
  • Minimal Allocations: Reuses data structures where possible

Thread Safety

All housing operations are thread-safe:

  • sync.RWMutex protects shared data structures
  • Database operations use connection pooling
  • Concurrent access to houses is properly synchronized

Future Enhancements

Potential areas for extension:

  • House decoration and furniture systems
  • Guild halls with special permissions
  • Real estate marketplace for player trading
  • Rental system for temporary housing
  • Advanced statistics and reporting
  • Integration with crafting systems