288 lines
6.7 KiB
Go
288 lines
6.7 KiB
Go
package appearances
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// Appearances manages a collection of appearance objects with thread-safe operations
|
|
type Appearances struct {
|
|
appearanceMap map[int32]*Appearance // Map of appearance ID to appearance
|
|
mutex sync.RWMutex // Thread safety for concurrent access
|
|
}
|
|
|
|
// NewAppearances creates a new appearances manager
|
|
func NewAppearances() *Appearances {
|
|
return &Appearances{
|
|
appearanceMap: make(map[int32]*Appearance),
|
|
}
|
|
}
|
|
|
|
// Reset clears all appearances from the manager
|
|
func (a *Appearances) Reset() {
|
|
a.ClearAppearances()
|
|
}
|
|
|
|
// ClearAppearances removes all appearances from the manager
|
|
func (a *Appearances) ClearAppearances() {
|
|
a.mutex.Lock()
|
|
defer a.mutex.Unlock()
|
|
|
|
// Clear the map - Go's garbage collector will handle cleanup
|
|
a.appearanceMap = make(map[int32]*Appearance)
|
|
}
|
|
|
|
// InsertAppearance adds an appearance to the manager
|
|
func (a *Appearances) InsertAppearance(appearance *Appearance) error {
|
|
if appearance == nil {
|
|
return fmt.Errorf("appearance cannot be nil")
|
|
}
|
|
|
|
a.mutex.Lock()
|
|
defer a.mutex.Unlock()
|
|
|
|
a.appearanceMap[appearance.GetID()] = appearance
|
|
return nil
|
|
}
|
|
|
|
// FindAppearanceByID retrieves an appearance by its ID
|
|
func (a *Appearances) FindAppearanceByID(id int32) *Appearance {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
if appearance, exists := a.appearanceMap[id]; exists {
|
|
return appearance
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HasAppearance checks if an appearance exists by ID
|
|
func (a *Appearances) HasAppearance(id int32) bool {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
_, exists := a.appearanceMap[id]
|
|
return exists
|
|
}
|
|
|
|
// GetAppearanceCount returns the total number of appearances
|
|
func (a *Appearances) GetAppearanceCount() int {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
return len(a.appearanceMap)
|
|
}
|
|
|
|
// GetAllAppearances returns a copy of all appearances
|
|
func (a *Appearances) GetAllAppearances() map[int32]*Appearance {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
// Return a copy to prevent external modification
|
|
result := make(map[int32]*Appearance)
|
|
for id, appearance := range a.appearanceMap {
|
|
result[id] = appearance
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GetAppearanceIDs returns all appearance IDs
|
|
func (a *Appearances) GetAppearanceIDs() []int32 {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
ids := make([]int32, 0, len(a.appearanceMap))
|
|
for id := range a.appearanceMap {
|
|
ids = append(ids, id)
|
|
}
|
|
|
|
return ids
|
|
}
|
|
|
|
// FindAppearancesByName finds all appearances with names containing the given substring
|
|
func (a *Appearances) FindAppearancesByName(nameSubstring string) []*Appearance {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
var results []*Appearance
|
|
|
|
for _, appearance := range a.appearanceMap {
|
|
if contains(appearance.GetName(), nameSubstring) {
|
|
results = append(results, appearance)
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
// FindAppearancesByMinClient finds all appearances with a specific minimum client version
|
|
func (a *Appearances) FindAppearancesByMinClient(minClient int16) []*Appearance {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
var results []*Appearance
|
|
|
|
for _, appearance := range a.appearanceMap {
|
|
if appearance.GetMinClientVersion() == minClient {
|
|
results = append(results, appearance)
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
// GetCompatibleAppearances returns all appearances compatible with the given client version
|
|
func (a *Appearances) GetCompatibleAppearances(clientVersion int16) []*Appearance {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
var results []*Appearance
|
|
|
|
for _, appearance := range a.appearanceMap {
|
|
if appearance.IsCompatibleWithClient(clientVersion) {
|
|
results = append(results, appearance)
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
// RemoveAppearance removes an appearance by ID
|
|
func (a *Appearances) RemoveAppearance(id int32) bool {
|
|
a.mutex.Lock()
|
|
defer a.mutex.Unlock()
|
|
|
|
if _, exists := a.appearanceMap[id]; exists {
|
|
delete(a.appearanceMap, id)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// UpdateAppearance updates an existing appearance or inserts it if it doesn't exist
|
|
func (a *Appearances) UpdateAppearance(appearance *Appearance) error {
|
|
if appearance == nil {
|
|
return fmt.Errorf("appearance cannot be nil")
|
|
}
|
|
|
|
a.mutex.Lock()
|
|
defer a.mutex.Unlock()
|
|
|
|
a.appearanceMap[appearance.GetID()] = appearance
|
|
return nil
|
|
}
|
|
|
|
// GetAppearancesByIDRange returns all appearances within the given ID range (inclusive)
|
|
func (a *Appearances) GetAppearancesByIDRange(minID, maxID int32) []*Appearance {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
var results []*Appearance
|
|
|
|
for id, appearance := range a.appearanceMap {
|
|
if id >= minID && id <= maxID {
|
|
results = append(results, appearance)
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
// ValidateAppearances checks all appearances for consistency
|
|
func (a *Appearances) ValidateAppearances() []string {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
var issues []string
|
|
|
|
for id, appearance := range a.appearanceMap {
|
|
if appearance == nil {
|
|
issues = append(issues, fmt.Sprintf("Appearance ID %d is nil", id))
|
|
continue
|
|
}
|
|
|
|
if appearance.GetID() != id {
|
|
issues = append(issues, fmt.Sprintf("Appearance ID mismatch: map key %d != appearance ID %d", id, appearance.GetID()))
|
|
}
|
|
|
|
if len(appearance.GetName()) == 0 {
|
|
issues = append(issues, fmt.Sprintf("Appearance ID %d has empty name", id))
|
|
}
|
|
|
|
if appearance.GetMinClientVersion() < 0 {
|
|
issues = append(issues, fmt.Sprintf("Appearance ID %d has negative min client version: %d", id, appearance.GetMinClientVersion()))
|
|
}
|
|
}
|
|
|
|
return issues
|
|
}
|
|
|
|
// IsValid returns true if all appearances are valid
|
|
func (a *Appearances) IsValid() bool {
|
|
issues := a.ValidateAppearances()
|
|
return len(issues) == 0
|
|
}
|
|
|
|
// GetStatistics returns statistics about the appearance collection
|
|
func (a *Appearances) GetStatistics() map[string]interface{} {
|
|
a.mutex.RLock()
|
|
defer a.mutex.RUnlock()
|
|
|
|
stats := make(map[string]interface{})
|
|
stats["total_appearances"] = len(a.appearanceMap)
|
|
|
|
// Count by minimum client version
|
|
versionCounts := make(map[int16]int)
|
|
for _, appearance := range a.appearanceMap {
|
|
versionCounts[appearance.GetMinClientVersion()]++
|
|
}
|
|
stats["appearances_by_min_client"] = versionCounts
|
|
|
|
// Find ID range
|
|
if len(a.appearanceMap) > 0 {
|
|
var minID, maxID int32
|
|
first := true
|
|
|
|
for id := range a.appearanceMap {
|
|
if first {
|
|
minID = id
|
|
maxID = id
|
|
first = false
|
|
} else {
|
|
if id < minID {
|
|
minID = id
|
|
}
|
|
if id > maxID {
|
|
maxID = id
|
|
}
|
|
}
|
|
}
|
|
|
|
stats["min_id"] = minID
|
|
stats["max_id"] = maxID
|
|
stats["id_range"] = maxID - minID
|
|
}
|
|
|
|
return stats
|
|
}
|
|
|
|
// contains checks if a string contains a substring (case-sensitive)
|
|
func contains(str, substr string) bool {
|
|
if len(substr) == 0 {
|
|
return true
|
|
}
|
|
if len(str) < len(substr) {
|
|
return false
|
|
}
|
|
|
|
for i := 0; i <= len(str)-len(substr); i++ {
|
|
if str[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
} |