eq2go/internal/appearances/interfaces.go

309 lines
8.0 KiB
Go

package appearances
import (
"fmt"
"sync"
)
// Database interface for appearance persistence
type Database interface {
LoadAllAppearances() ([]*Appearance, error)
SaveAppearance(appearance *Appearance) error
DeleteAppearance(id int32) error
LoadAppearancesByClientVersion(minClientVersion int16) ([]*Appearance, error)
}
// Logger interface for appearance logging
type Logger interface {
LogInfo(message string, args ...interface{})
LogError(message string, args ...interface{})
LogDebug(message string, args ...interface{})
LogWarning(message string, args ...interface{})
}
// AppearanceProvider interface for entities that provide appearances
type AppearanceProvider interface {
GetAppearanceID() int32
SetAppearanceID(id int32)
GetAppearance() *Appearance
IsCompatibleWithClient(clientVersion int16) bool
}
// AppearanceAware interface for entities that use appearances
type AppearanceAware interface {
GetAppearanceManager() *Manager
FindAppearanceByID(id int32) *Appearance
GetCompatibleAppearances(clientVersion int16) []*Appearance
}
// Client interface for appearance-related client operations
type Client interface {
GetVersion() int16
SendAppearanceUpdate(appearanceID int32) error
}
// AppearanceCache interface for caching appearance data
type AppearanceCache interface {
Get(id int32) *Appearance
Set(id int32, appearance *Appearance)
Remove(id int32)
Clear()
GetSize() int
}
// EntityAppearanceAdapter provides appearance functionality for entities
type EntityAppearanceAdapter struct {
entity Entity
appearanceID int32
manager *Manager
logger Logger
}
// Entity interface for things that can have appearances
type Entity interface {
GetID() int32
GetName() string
GetDatabaseID() int32
}
// NewEntityAppearanceAdapter creates a new entity appearance adapter
func NewEntityAppearanceAdapter(entity Entity, manager *Manager, logger Logger) *EntityAppearanceAdapter {
return &EntityAppearanceAdapter{
entity: entity,
appearanceID: 0,
manager: manager,
logger: logger,
}
}
// GetAppearanceID returns the entity's appearance ID
func (eaa *EntityAppearanceAdapter) GetAppearanceID() int32 {
return eaa.appearanceID
}
// SetAppearanceID sets the entity's appearance ID
func (eaa *EntityAppearanceAdapter) SetAppearanceID(id int32) {
eaa.appearanceID = id
if eaa.logger != nil {
eaa.logger.LogDebug("Entity %d (%s): Set appearance ID to %d",
eaa.entity.GetID(), eaa.entity.GetName(), id)
}
}
// GetAppearance returns the entity's appearance object
func (eaa *EntityAppearanceAdapter) GetAppearance() *Appearance {
if eaa.appearanceID == 0 {
return nil
}
if eaa.manager == nil {
if eaa.logger != nil {
eaa.logger.LogError("Entity %d (%s): No appearance manager available",
eaa.entity.GetID(), eaa.entity.GetName())
}
return nil
}
return eaa.manager.FindAppearanceByID(eaa.appearanceID)
}
// IsCompatibleWithClient checks if the entity's appearance is compatible with client version
func (eaa *EntityAppearanceAdapter) IsCompatibleWithClient(clientVersion int16) bool {
appearance := eaa.GetAppearance()
if appearance == nil {
return true // No appearance means compatible with all clients
}
return appearance.IsCompatibleWithClient(clientVersion)
}
// GetAppearanceName returns the name of the entity's appearance
func (eaa *EntityAppearanceAdapter) GetAppearanceName() string {
appearance := eaa.GetAppearance()
if appearance == nil {
return ""
}
return appearance.GetName()
}
// ValidateAppearance validates that the entity's appearance exists and is valid
func (eaa *EntityAppearanceAdapter) ValidateAppearance() error {
if eaa.appearanceID == 0 {
return nil // No appearance is valid
}
appearance := eaa.GetAppearance()
if appearance == nil {
return fmt.Errorf("appearance ID %d not found", eaa.appearanceID)
}
return nil
}
// UpdateAppearance updates the entity's appearance from the manager
func (eaa *EntityAppearanceAdapter) UpdateAppearance(id int32) error {
if eaa.manager == nil {
return fmt.Errorf("no appearance manager available")
}
appearance := eaa.manager.FindAppearanceByID(id)
if appearance == nil {
return fmt.Errorf("appearance ID %d not found", id)
}
eaa.SetAppearanceID(id)
if eaa.logger != nil {
eaa.logger.LogInfo("Entity %d (%s): Updated appearance to %d (%s)",
eaa.entity.GetID(), eaa.entity.GetName(), id, appearance.GetName())
}
return nil
}
// SendAppearanceToClient sends the appearance to a client
func (eaa *EntityAppearanceAdapter) SendAppearanceToClient(client Client) error {
if client == nil {
return fmt.Errorf("client is nil")
}
if eaa.appearanceID == 0 {
return nil // No appearance to send
}
// Check client compatibility
if !eaa.IsCompatibleWithClient(client.GetVersion()) {
if eaa.logger != nil {
eaa.logger.LogWarning("Entity %d (%s): Appearance %d not compatible with client version %d",
eaa.entity.GetID(), eaa.entity.GetName(), eaa.appearanceID, client.GetVersion())
}
return fmt.Errorf("appearance not compatible with client version %d", client.GetVersion())
}
return client.SendAppearanceUpdate(eaa.appearanceID)
}
// SimpleAppearanceCache is a basic in-memory appearance cache
type SimpleAppearanceCache struct {
cache map[int32]*Appearance
mutex sync.RWMutex
}
// NewSimpleAppearanceCache creates a new simple appearance cache
func NewSimpleAppearanceCache() *SimpleAppearanceCache {
return &SimpleAppearanceCache{
cache: make(map[int32]*Appearance),
}
}
// Get retrieves an appearance from cache
func (sac *SimpleAppearanceCache) Get(id int32) *Appearance {
sac.mutex.RLock()
defer sac.mutex.RUnlock()
return sac.cache[id]
}
// Set stores an appearance in cache
func (sac *SimpleAppearanceCache) Set(id int32, appearance *Appearance) {
sac.mutex.Lock()
defer sac.mutex.Unlock()
sac.cache[id] = appearance
}
// Remove removes an appearance from cache
func (sac *SimpleAppearanceCache) Remove(id int32) {
sac.mutex.Lock()
defer sac.mutex.Unlock()
delete(sac.cache, id)
}
// Clear removes all appearances from cache
func (sac *SimpleAppearanceCache) Clear() {
sac.mutex.Lock()
defer sac.mutex.Unlock()
sac.cache = make(map[int32]*Appearance)
}
// GetSize returns the number of cached appearances
func (sac *SimpleAppearanceCache) GetSize() int {
sac.mutex.RLock()
defer sac.mutex.RUnlock()
return len(sac.cache)
}
// CachedAppearanceManager wraps a Manager with caching functionality
type CachedAppearanceManager struct {
*Manager
cache AppearanceCache
}
// NewCachedAppearanceManager creates a new cached appearance manager
func NewCachedAppearanceManager(manager *Manager, cache AppearanceCache) *CachedAppearanceManager {
return &CachedAppearanceManager{
Manager: manager,
cache: cache,
}
}
// FindAppearanceByID finds an appearance with caching
func (cam *CachedAppearanceManager) FindAppearanceByID(id int32) *Appearance {
// Check cache first
if appearance := cam.cache.Get(id); appearance != nil {
return appearance
}
// Load from manager
appearance := cam.Manager.FindAppearanceByID(id)
if appearance != nil {
// Cache the result
cam.cache.Set(id, appearance)
}
return appearance
}
// AddAppearance adds an appearance and updates cache
func (cam *CachedAppearanceManager) AddAppearance(appearance *Appearance) error {
err := cam.Manager.AddAppearance(appearance)
if err == nil {
// Update cache
cam.cache.Set(appearance.GetID(), appearance)
}
return err
}
// UpdateAppearance updates an appearance and cache
func (cam *CachedAppearanceManager) UpdateAppearance(appearance *Appearance) error {
err := cam.Manager.UpdateAppearance(appearance)
if err == nil {
// Update cache
cam.cache.Set(appearance.GetID(), appearance)
}
return err
}
// RemoveAppearance removes an appearance and updates cache
func (cam *CachedAppearanceManager) RemoveAppearance(id int32) error {
err := cam.Manager.RemoveAppearance(id)
if err == nil {
// Remove from cache
cam.cache.Remove(id)
}
return err
}
// ClearCache clears the appearance cache
func (cam *CachedAppearanceManager) ClearCache() {
cam.cache.Clear()
}