package skills import ( "sync" ) // MasterSkillList manages the master list of all available skills type MasterSkillList struct { skills map[int32]*Skill // All skills by ID populatePackets map[int16][]byte // Cached packets by version mutex sync.RWMutex // Thread safety } // NewMasterSkillList creates a new master skill list func NewMasterSkillList() *MasterSkillList { return &MasterSkillList{ skills: make(map[int32]*Skill), populatePackets: make(map[int16][]byte), } } // AddSkill adds a skill to the master list func (msl *MasterSkillList) AddSkill(skill *Skill) { if skill == nil { return } msl.mutex.Lock() defer msl.mutex.Unlock() msl.skills[skill.SkillID] = skill // Clear cached packets when skills change msl.populatePackets = make(map[int16][]byte) } // GetSkillCount returns the total number of skills func (msl *MasterSkillList) GetSkillCount() int16 { msl.mutex.RLock() defer msl.mutex.RUnlock() return int16(len(msl.skills)) } // GetAllSkills returns a copy of all skills func (msl *MasterSkillList) GetAllSkills() map[int32]*Skill { msl.mutex.RLock() defer msl.mutex.RUnlock() // Return a copy to prevent external modification skills := make(map[int32]*Skill) for id, skill := range msl.skills { skills[id] = skill } return skills } // GetSkill returns a skill by ID func (msl *MasterSkillList) GetSkill(skillID int32) *Skill { msl.mutex.RLock() defer msl.mutex.RUnlock() if skill, exists := msl.skills[skillID]; exists { return skill } return nil } // GetSkillByName returns a skill by name (case-insensitive) func (msl *MasterSkillList) GetSkillByName(skillName string) *Skill { msl.mutex.RLock() defer msl.mutex.RUnlock() // Convert to lowercase for comparison lowerName := toLower(skillName) for _, skill := range msl.skills { if toLower(skill.Name.Data) == lowerName { return skill } } return nil } // GetPopulateSkillsPacket builds a packet containing all skills for a client version func (msl *MasterSkillList) GetPopulateSkillsPacket(version int16) ([]byte, error) { msl.mutex.Lock() defer msl.mutex.Unlock() // Check if we have a cached packet for this version if packet, exists := msl.populatePackets[version]; exists { // Return a copy of the cached packet result := make([]byte, len(packet)) copy(result, packet) return result, nil } // Build the packet - this is a placeholder implementation // In the full implementation, this would use the PacketStruct system // to build a proper WS_SkillMap packet for the given version packet := msl.buildSkillMapPacket(version) // Cache the packet msl.populatePackets[version] = packet // Return a copy result := make([]byte, len(packet)) copy(result, packet) return result, nil } // buildSkillMapPacket builds a WS_SkillMap packet func (msl *MasterSkillList) buildSkillMapPacket(version int16) []byte { // This is a placeholder implementation // In a real implementation, this would use the PacketStruct system: // packet := configReader.getStruct("WS_SkillMap", version) // packet.setArrayLengthByName("skill_count", len(msl.skills)) // for i, skill := range msl.skills { // packet.setArrayDataByName("skill_id", skill.SkillID, i) // packet.setArrayDataByName("short_name", &skill.ShortName, i) // packet.setArrayDataByName("name", &skill.Name, i) // packet.setArrayDataByName("description", &skill.Description, i) // } // return packet.serialize() // For now, return an empty packet return make([]byte, 0) } // RemoveSkill removes a skill from the master list func (msl *MasterSkillList) RemoveSkill(skillID int32) { msl.mutex.Lock() defer msl.mutex.Unlock() delete(msl.skills, skillID) // Clear cached packets when skills change msl.populatePackets = make(map[int16][]byte) } // ClearSkills removes all skills from the master list func (msl *MasterSkillList) ClearSkills() { msl.mutex.Lock() defer msl.mutex.Unlock() msl.skills = make(map[int32]*Skill) msl.populatePackets = make(map[int16][]byte) } // GetSkillsByType returns all skills of a specific type func (msl *MasterSkillList) GetSkillsByType(skillType int32) []*Skill { msl.mutex.RLock() defer msl.mutex.RUnlock() var skills []*Skill for _, skill := range msl.skills { if skill.SkillType == skillType { skills = append(skills, skill) } } return skills } // HasSkill checks if a skill exists in the master list func (msl *MasterSkillList) HasSkill(skillID int32) bool { msl.mutex.RLock() defer msl.mutex.RUnlock() _, exists := msl.skills[skillID] return exists } // GetSkillIDs returns all skill IDs func (msl *MasterSkillList) GetSkillIDs() []int32 { msl.mutex.RLock() defer msl.mutex.RUnlock() ids := make([]int32, 0, len(msl.skills)) for id := range msl.skills { ids = append(ids, id) } return ids } // toLower converts a string to lowercase (simple implementation) func toLower(s string) string { result := make([]byte, len(s)) for i, c := range []byte(s) { if c >= 'A' && c <= 'Z' { result[i] = c + 32 } else { result[i] = c } } return string(result) }