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 processingEnableForeclosure
: Allow foreclosure of houses with overdue upkeepUpkeepGracePeriod
: Grace period in seconds before foreclosureMaxHousesPerPlayer
: Maximum houses per characterEnableStatistics
: 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/upkeepHouseErrorAlignmentRestriction
: Player alignment doesn't meet requirementsHouseErrorGuildLevelRestriction
: Player guild level too lowHouseErrorMaxHousesReached
: Player at house limitHouseErrorHouseNotFound
: 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