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() }