309 lines
7.9 KiB
Go
309 lines
7.9 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 ...any)
|
|
LogError(message string, args ...any)
|
|
LogDebug(message string, args ...any)
|
|
LogWarning(message string, args ...any)
|
|
}
|
|
|
|
// 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()
|
|
}
|