// // LNGameMateManager.swift // Lanu // // Created by OneeChan on 2025/11/20. // import Foundation protocol LNGameMateManagerNotify { func onGameMateManagerInfoChanged() func onGameTypesChanged() func onAutoReplyCreated(item: LNAutoReplyVO) func onAutoReplyDeleted(id: String) func onAutoReplyModified(item: LNAutoReplyVO) } extension LNGameMateManagerNotify { func onGameMateManagerInfoChanged() { } func onGameTypesChanged() { } func onAutoReplyCreated(item: LNAutoReplyVO) { } func onAutoReplyDeleted(id: String) { } func onAutoReplyModified(item: LNAutoReplyVO) { } } var myGameMateInfo: LNGameMateManagerInfo? { LNGameMateManager.shared.myGameMateInfo } class LNGameMateManager { static let shared = LNGameMateManager() private(set) var curGameTypes: [LNGameTypeItemVO] = [] private(set) var gameFilterMap: [String: [LNSkillFilterField]] = [:] private(set) var myGameMateInfo: LNGameMateManagerInfo? static let gameSelectionMaxCount = 5 static let AutoReplayMaxInput = 500 func gameCategory(for code: String) -> LNGameCategoryItemVO? { for type in curGameTypes { if let item = type.children.first(where: { $0.code == code }) { return item } } return nil } func gameFilter(for code: String) -> [LNSkillFilterField] { gameFilterMap[code] ?? [] } private init() { LNEventDeliver.addObserver(self) } } // MARK: 陪玩师信息拉取 extension LNGameMateManager { func getUserSkills(uid: String, queue: DispatchQueue = .main, handler: @escaping ([LNGameMateSkillVO]?) -> Void) { LNHttpManager.shared.getUserSkills(uid: uid) { res, err in guard err == nil, let res else { queue.asyncIfNotGlobal { handler(nil) } return } queue.asyncIfNotGlobal { handler(res.list) } } } func getSkillDetail(skillId: String, queue: DispatchQueue = .main, handler: @escaping (LNGameMateSkillDetailVO?) -> Void) { LNHttpManager.shared.getSkillDetail(skillId: skillId) { res, err in guard err == nil, let res else { queue.asyncIfNotGlobal { handler(nil) } return } queue.asyncIfNotGlobal { handler(res) } } } func scoreGameMate(uid: String, score: Int, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.scoreGameMate(uid: uid, score: score) { err in queue.asyncIfNotGlobal { handler(err == nil) } } } func getSkillCommentList(id: String, next: String? = nil, queue: DispatchQueue = .main, handler: @escaping (LNSkillCommentListResponse?) -> Void) { LNHttpManager.shared.getSkillCommentList(id: id, size: 30, next: next ?? "") { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } func getGameMateList( topCategory: String, category: String?, filter: LNGameMateFilter, size: Int, next: String?, queue: DispatchQueue = .main, handler: @escaping ([LNGameMateListItemVO]?, String?) -> Void) { LNHttpManager.shared.getGameMateList( topCategory: topCategory, category: category, filter: filter, size: size, next: next ?? "") { res, err in queue.asyncIfNotGlobal { handler(res?.list, res?.next) } if let err { showToast(err.errorDesc) } } LNRoomManager.shared.reloadHallEntrance() } func searchGameMate(keyword: String, next: String, queue: DispatchQueue = .main, handler: @escaping ([LNGameMateSearchResultVO]?, String?) -> Void) { LNHttpManager.shared.searchGameMate(keyword: keyword, size: 30, next: next) { res, err in queue.asyncIfNotGlobal { handler(res?.list, res?.next) } if let err { showToast(err.errorDesc) } } } func mixSearch(keyword: String, queue: DispatchQueue = .main, handler: @escaping (LNMixSearchResponse?) -> Void) { LNHttpManager.shared.mixSearch(keyword: keyword) { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } } // MARK: 陪玩师类别 extension LNGameMateManager { func getGameTypeList(queue: DispatchQueue = .main, handler: @escaping ([LNGameTypeItemVO]?) -> Void) { LNHttpManager.shared.getGameCategories { [weak self] res, err in guard let self else { return } guard err == nil, let res else { queue.asyncIfNotGlobal { handler(nil) } return } reloadGameFilterConfig() curGameTypes = res.list queue.asyncIfNotGlobal { handler(res.list) } notifyGameTypesChanged() } } func reloadGameFilterConfig() { LNHttpManager.shared.getGameFilterConfig { [weak self] list, err in guard let self else { return } guard let list else { return } gameFilterMap.removeAll() for item in list.list { gameFilterMap[item.code] = item.filterFields } } } } // MARK: 陪玩师入驻 extension LNGameMateManager { func getJoinGameMateInfo(queue: DispatchQueue = .main, handler: @escaping (LNJoinUsInputInfosResponse?) -> Void) { LNHttpManager.shared.getJoinGameMateInfo { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } func setJoinGameMateBaseInfo(info: LNJoinUsBaseInfoVO, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.setJoinGameMateBaseInfo(info: info) { res, err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } } } func getCreateSkillFields(id: String, queue: DispatchQueue = .main, handler: @escaping (LNCreateSkillInputFieldsVO?) -> Void) { LNHttpManager.shared.getCreateSkillFields(id: id) { res, err in queue.asyncIfNotGlobal { if let res { guard !res.fields.isEmpty else { showToast(.init(key: "B00060")) handler(nil) return } guard res.isAvailable else { showToast(.init(key: "B00058")) handler(nil) return } } handler(res) } if let err { showToast(err.errorDesc) } } } func createSkill(info: LNCreateSkillFieldsInfo, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.createSkill(info: info) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } } } } // MARK: 陪玩师管理 extension LNGameMateManager { func getGameMateManagerInfo( queue: DispatchQueue = .main, handler: ((LNGameMateManagerInfo?) -> Void)? = nil) { LNHttpManager.shared.getGameMateManagerInfo { [weak self] info, err in queue.asyncIfNotGlobal { handler?(info) } if let err { showToast(err.errorDesc) } else { guard let self else { return } myGameMateInfo = info notifyUserGameMateManagerInfoChanged() } } } func enableGameMate(open: Bool, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.enableGameMate(open: open) { [weak self] err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } else { guard let self else { return } getGameMateManagerInfo() } } } func getOrderAccetpConfig( queue: DispatchQueue = .main, handler: @escaping (LNOrderAcceptConfig?) -> Void) { LNHttpManager.shared.getOrderAccetpConfig { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } func setOrderAcceptConfig( config: LNOrderAcceptConfig, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.setOrderAcceptConfig(config: config) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } } } func getMySkillList( queue: DispatchQueue = .main, handler: @escaping (LNMySkillListResponse?) -> Void) { LNHttpManager.shared.getMySkillList { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } func getSkillSwitchInfo(id: String, queue: DispatchQueue = .main, handler: @escaping (LNSkillSwitchResponse?) -> Void) { LNHttpManager.shared.getSkillSwitchInfo(id: id) { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } func enableSkill(skillId: String, open: Bool, mainSkill: Bool? = nil, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.enableSkill(skillId: skillId, open: open, mainSkill: mainSkill) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } else { LNProfileManager.shared.reloadMyProfileDetail() } } } func getVisitorsList(next: String? = nil, queue: DispatchQueue = .main, handler: @escaping ([LNVisitorItemVO]?, String?) -> Void) { LNHttpManager.shared.getVisitorsList(next: next ?? "", size: 30) { res, err in queue.asyncIfNotGlobal { handler(res?.list, res?.next) } if let err { showToast(err.errorDesc) } } } func getSkillEditFields(id: String, queue: DispatchQueue = .main, handler: @escaping (LNSkillEditFieldsResponse?) -> Void) { LNHttpManager.shared.getSkillEditFields(id: id) { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } func commitSkillEdit(info: LNEditSkillFieldsInfo, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.commitSkillEdit(info: info) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } } } } // MARK: 欢迎语(自动回复) extension LNGameMateManager { func enableAutoReplay(on: Bool, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.enableAutoReplay(on: on) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } } } func getAutoReplayList(queue: DispatchQueue = .main, handler: @escaping (LNAutoReplyResponse?) -> Void) { LNHttpManager.shared.getAutoReplayList { list, err in queue.asyncIfNotGlobal { handler(list) } if let err { showToast(err.errorDesc) } } } func deleteAutoReplay(id: String, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.deleteAutoReplay(id: id) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } else { Self.notifyAutoReplayDeleted(id: id) } } } func createAutoReplay(item: LNAutoReplyVO, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.createAutoReplay(item: item) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } else { Self.notifyAutoReplayCreated(item: item) } } } func updateAutoReplay(item: LNAutoReplyVO, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.updateAutoReplay(item: item) { err in queue.asyncIfNotGlobal { handler(err == nil) } if let err { showToast(err.errorDesc) } else { Self.notifyAutoReplayModified(item: item) } } } func triggerAutoReplayIfNeed(uid: String) { LNHttpManager.shared.triggerAutoReplayIfNeed(uid: uid) { _ in } } func markUseAutoReplay(uid: String) { LNHttpManager.shared.markUseAutoReplay(uid: uid) { _ in } } func fetchAutoReplyQuota(uid: String, queue: DispatchQueue = .main, handler: @escaping (Bool) -> Void) { LNHttpManager.shared.fetchAutoReplyQuota(uid: uid) { res, err in queue.asyncIfNotGlobal { if let err { showToast(err.errorDesc) handler(false) } else if let res { if res.playmateQuotaCount > 0 && res.userQuotaCount > 0 { handler(true) } else { showToast(.init(key: "A00350")) handler(false) } } else { handler(false) } } } } } // MARK: 潜在用户 extension LNGameMateManager { func getPotentialUsers(queue: DispatchQueue = .main, handler: @escaping (LNPotentialUsersResponse?) -> Void) { LNHttpManager.shared.getPotentialUsers { res, err in queue.asyncIfNotGlobal { handler(res) } if let err { showToast(err.errorDesc) } } } } extension LNGameMateManager: LNProfileManagerNotify { func onUserInfoChanged(userInfo: LNUserProfileVO) { guard userInfo.userNo.isMyUid else { return } if userInfo.playmate { getGameMateManagerInfo() } } } extension LNGameMateManager { private func notifyUserGameMateManagerInfoChanged() { LNEventDeliver.notifyEvent { ($0 as? LNGameMateManagerNotify)?.onGameMateManagerInfoChanged() } } private func notifyGameTypesChanged() { LNEventDeliver.notifyEvent { ($0 as? LNGameMateManagerNotify)?.onGameTypesChanged() } } private static func notifyAutoReplayCreated(item: LNAutoReplyVO) { LNEventDeliver.notifyEvent { ($0 as? LNGameMateManagerNotify)?.onAutoReplyCreated(item: item) } } private static func notifyAutoReplayDeleted(id: String) { LNEventDeliver.notifyEvent { ($0 as? LNGameMateManagerNotify)?.onAutoReplyDeleted(id: id) } } private static func notifyAutoReplayModified(item: LNAutoReplyVO) { LNEventDeliver.notifyEvent { ($0 as? LNGameMateManagerNotify)?.onAutoReplyModified(item: item) } } }