package object import ( "fmt" "sync" ) // ObjectManager manages all objects in the game world type ObjectManager struct { objects map[int32]*Object // Objects by database ID objectsByZone map[string][]*Object // Objects grouped by zone mutex sync.RWMutex // Thread safety } // NewObjectManager creates a new object manager func NewObjectManager() *ObjectManager { return &ObjectManager{ objects: make(map[int32]*Object), objectsByZone: make(map[string][]*Object), } } // AddObject adds an object to the manager func (om *ObjectManager) AddObject(object *Object) error { if object == nil { return fmt.Errorf("cannot add nil object") } if err := object.Validate(); err != nil { return fmt.Errorf("invalid object: %w", err) } om.mutex.Lock() defer om.mutex.Unlock() databaseID := object.GetDatabaseID() if databaseID == 0 { return fmt.Errorf("object must have a valid database ID") } // Check if object already exists if _, exists := om.objects[databaseID]; exists { return fmt.Errorf("object with database ID %d already exists", databaseID) } // Add to main index om.objects[databaseID] = object // Add to zone index zoneName := object.GetZone() if zoneName != "" { om.objectsByZone[zoneName] = append(om.objectsByZone[zoneName], object) } return nil } // RemoveObject removes an object from the manager func (om *ObjectManager) RemoveObject(databaseID int32) error { om.mutex.Lock() defer om.mutex.Unlock() object, exists := om.objects[databaseID] if !exists { return fmt.Errorf("object with database ID %d not found", databaseID) } // Remove from main index delete(om.objects, databaseID) // Remove from zone index zoneName := object.GetZone() if zoneName != "" { objects := om.objectsByZone[zoneName] for i, obj := range objects { if obj.GetDatabaseID() == databaseID { // Remove from slice om.objectsByZone[zoneName] = append(objects[:i], objects[i+1:]...) break } } // Clean up empty zone entries if len(om.objectsByZone[zoneName]) == 0 { delete(om.objectsByZone, zoneName) } } return nil } // GetObject retrieves an object by database ID func (om *ObjectManager) GetObject(databaseID int32) *Object { om.mutex.RLock() defer om.mutex.RUnlock() return om.objects[databaseID] } // GetObjectsByZone retrieves all objects in a specific zone func (om *ObjectManager) GetObjectsByZone(zoneName string) []*Object { om.mutex.RLock() defer om.mutex.RUnlock() objects := om.objectsByZone[zoneName] if objects == nil { return []*Object{} } // Return a copy to prevent external modification result := make([]*Object, len(objects)) copy(result, objects) return result } // GetObjectsByType retrieves objects by their type func (om *ObjectManager) GetObjectsByType(objectType string) []*Object { om.mutex.RLock() defer om.mutex.RUnlock() var result []*Object for _, object := range om.objects { if object.GetObjectType() == objectType { result = append(result, object) } } return result } // GetInteractiveObjects returns all objects that can be interacted with func (om *ObjectManager) GetInteractiveObjects() []*Object { om.mutex.RLock() defer om.mutex.RUnlock() var result []*Object for _, object := range om.objects { if object.CanInteract() { result = append(result, object) } } return result } // GetMerchantObjects returns all merchant objects func (om *ObjectManager) GetMerchantObjects() []*Object { om.mutex.RLock() defer om.mutex.RUnlock() var result []*Object for _, object := range om.objects { if object.IsMerchant() { result = append(result, object) } } return result } // GetTransportObjects returns all transport objects func (om *ObjectManager) GetTransportObjects() []*Object { om.mutex.RLock() defer om.mutex.RUnlock() var result []*Object for _, object := range om.objects { if object.IsTransporter() { result = append(result, object) } } return result } // GetCollectorObjects returns all collector objects func (om *ObjectManager) GetCollectorObjects() []*Object { om.mutex.RLock() defer om.mutex.RUnlock() var result []*Object for _, object := range om.objects { if object.IsCollector() { result = append(result, object) } } return result } // UpdateObjectZone updates an object's zone (called when object moves zones) func (om *ObjectManager) UpdateObjectZone(databaseID int32, newZoneName string) error { om.mutex.Lock() defer om.mutex.Unlock() object, exists := om.objects[databaseID] if !exists { return fmt.Errorf("object with database ID %d not found", databaseID) } oldZoneName := object.GetZone() // Remove from old zone index if oldZoneName != "" { objects := om.objectsByZone[oldZoneName] for i, obj := range objects { if obj.GetDatabaseID() == databaseID { om.objectsByZone[oldZoneName] = append(objects[:i], objects[i+1:]...) break } } // Clean up empty zone entries if len(om.objectsByZone[oldZoneName]) == 0 { delete(om.objectsByZone, oldZoneName) } } // Update object zone object.SetZone(newZoneName) // Add to new zone index if newZoneName != "" { om.objectsByZone[newZoneName] = append(om.objectsByZone[newZoneName], object) } return nil } // GetObjectCount returns the total number of objects func (om *ObjectManager) GetObjectCount() int { om.mutex.RLock() defer om.mutex.RUnlock() return len(om.objects) } // GetZoneCount returns the number of zones with objects func (om *ObjectManager) GetZoneCount() int { om.mutex.RLock() defer om.mutex.RUnlock() return len(om.objectsByZone) } // GetAllObjects returns all objects (use with caution for large datasets) func (om *ObjectManager) GetAllObjects() []*Object { om.mutex.RLock() defer om.mutex.RUnlock() result := make([]*Object, 0, len(om.objects)) for _, object := range om.objects { result = append(result, object) } return result } // Clear removes all objects from the manager func (om *ObjectManager) Clear() { om.mutex.Lock() defer om.mutex.Unlock() om.objects = make(map[int32]*Object) om.objectsByZone = make(map[string][]*Object) } // GetObjectStatistics returns statistics about objects in the manager func (om *ObjectManager) GetObjectStatistics() ObjectStatistics { om.mutex.RLock() defer om.mutex.RUnlock() stats := ObjectStatistics{ TotalObjects: len(om.objects), ZoneCount: len(om.objectsByZone), TypeCounts: make(map[string]int), } // Count by type for _, object := range om.objects { objectType := object.GetObjectType() stats.TypeCounts[objectType]++ } // Count interactive objects for _, object := range om.objects { if object.CanInteract() { stats.InteractiveObjects++ } } return stats } // ObjectStatistics contains statistics about objects type ObjectStatistics struct { TotalObjects int `json:"total_objects"` InteractiveObjects int `json:"interactive_objects"` ZoneCount int `json:"zone_count"` TypeCounts map[string]int `json:"type_counts"` } // Global object manager instance var globalObjectManager *ObjectManager var globalObjectManagerOnce sync.Once // GetGlobalObjectManager returns the global object manager instance func GetGlobalObjectManager() *ObjectManager { globalObjectManagerOnce.Do(func() { globalObjectManager = NewObjectManager() }) return globalObjectManager }