X-Git-Url: http://git.osdn.net/view?p=kcd%2FKCD.git;a=blobdiff_plain;f=KCD%2FShipMapper.swift;h=c03e83cc9972c7dce7eabe9ee6794753b0ae9f30;hp=fcdf534433a1cc7973b09579df51e3dce4e0927b;hb=e341ef2774c1d7a27d9eb60edab905f1adc510a3;hpb=e79eb51586427f81a13cc65e18587c542920c081 diff --git a/KCD/ShipMapper.swift b/KCD/ShipMapper.swift index fcdf5344..c03e83cc 100644 --- a/KCD/ShipMapper.swift +++ b/KCD/ShipMapper.swift @@ -9,172 +9,266 @@ import Cocoa import SwiftyJSON -fileprivate enum ShipAPI: String { - case getMemberShip = "/kcsapi/api_get_member/ship" - case port = "/kcsapi/api_port/port" - case getMemberShip3 = "/kcsapi/api_get_member/ship3" - case kousyouGetShip = "/kcsapi/api_req_kousyou/getship" - case getMemberShipDeck = "/kcsapi/api_get_member/ship_deck" - case kaisouPowerUp = "/kcsapi/api_req_kaisou/powerup" - case kaisouSlotDeprive = "/kcsapi/api_req_kaisou/slot_deprive" -} - -fileprivate func dataKeys(_ apiResponse: APIResponse) -> [String] { - guard let shipApi = ShipAPI(rawValue: apiResponse.api) - else { return ["api_data"] } - switch shipApi { - case .port: return ["api_data", "api_ship"] - case .getMemberShip3: return ["api_data", "api_ship_data"] - case .kousyouGetShip: return ["api_data", "api_ship"] - case .getMemberShipDeck: return ["api_data", "api_ship_data"] - case .kaisouPowerUp: return ["api_data", "api_ship"] - case .kaisouSlotDeprive: return ["api_data", "api_ship_data", "api_set_ship"] - case .getMemberShip: return ["api_data"] - } -} - -extension MappingConfiguration { - func change(dataKeys: [String]) -> MappingConfiguration { - return MappingConfiguration(entity: self.entity, - dataKeys: dataKeys, - primaryKeys: self.primaryKeys, - editorStore: self.editorStore, - ignoreKeys: self.ignoreKeys) - } -} - -class ShipMapper: JSONMapper { - typealias ObjectType = Ship +final class ShipMapper: JSONMapper { + + private static let ignoreKeys = ["api_gomes", "api_gomes2", "api_broken", "api_powup", + "api_voicef", "api_afterlv", "api_aftershipid", "api_backs", + "api_slotnum", "api_stype", "api_name", "api_yomi", + "api_raig", "api_luck", "api_saku", "api_raim", "api_baku", + "api_taik", "api_houg", "api_houm", "api_tyku", + "api_ndock_item", "api_star", + "api_ndock_time_str", "api_member_id", + "api_fuel_max", "api_bull_max"] + let apiResponse: APIResponse let configuration: MappingConfiguration required init(_ apiResponse: APIResponse) { + self.apiResponse = apiResponse - self.configuration = MappingConfiguration(entity: Ship.entity, - dataKeys: dataKeys(apiResponse), + self.configuration = MappingConfiguration(entity: Ship.self, + dataKeys: ShipMapper.dataKeys(apiResponse), editorStore: ServerDataStore.oneTimeEditor(), - ignoreKeys: - ["api_gomes", "api_gomes2", "api_broken", "api_powup", - "api_voicef", "api_afterlv", "api_aftershipid", "api_backs", - "api_slotnum", "api_stype", "api_name", "api_yomi", - "api_raig", "api_luck", "api_saku", "api_raim", "api_baku", - "api_taik", "api_houg", "api_houm", "api_tyku", - "api_ndock_item", "api_star", - "api_ndock_time_str", "api_member_id", - "api_fuel_max", "api_bull_max"]) - - // kaisouSlotDepriveでは同時に2種類のデータが入る - if let api = ShipAPI(rawValue: apiResponse.api), - api == .kaisouSlotDeprive { - let conf = self.configuration.change(dataKeys: ["api_data", "api_ship_data", "api_unset_ship"]) - ShipMapper(apiResponse, configuration: conf).commit() - } + ignoreKeys: ShipMapper.ignoreKeys) } - private init(_ apiResponse: APIResponse, configuration: MappingConfiguration) { + + // slotDepriveの時に2種類のデータが来るため + init(forSlotDepriveUnset apiResponse: APIResponse) { + self.apiResponse = apiResponse - self.configuration = configuration + self.configuration = MappingConfiguration(entity: Ship.self, + dataKeys: ["api_data", "api_ship_data", "api_unset_ship"], + editorStore: ServerDataStore.oneTimeEditor(), + ignoreKeys: ShipMapper.ignoreKeys) + } + + private class func dataKeys(_ apiResponse: APIResponse) -> [String] { + + switch apiResponse.api.endpoint { + + case .port, .getShip, .powerup: return ["api_data", "api_ship"] + + case .ship3, .shipDeck: return ["api_data", "api_ship_data"] + + case .slotDeprive: return ["api_data", "api_ship_data", "api_set_ship"] + + case .ship, .ship2: return ["api_data"] + + default: + + Logger.shared.log("Missing API: \(apiResponse.api)") + + return ["api_data"] + } } private var registerIds: [Int] = [] private lazy var masterShips: [MasterShip] = { - return ServerDataStore.default.sortedMasterShipsById() + + guard let store = configuration.editorStore as? ServerDataStore else { + + return [] + } + + return store.sortedMasterShipsById() + }() private lazy var slotItems: [SlotItem] = { - return ServerDataStore.default.sortedSlotItemsById() + + guard let store = configuration.editorStore as? ServerDataStore else { + + return [] + } + + return store.sortedSlotItemsById() }() - private var isDeleteNotExist: Bool { - guard let shipApi = ShipAPI(rawValue: apiResponse.api) - else { return true } - switch shipApi { - case .getMemberShip3, .kousyouGetShip, .getMemberShipDeck, - .kaisouPowerUp, .kaisouSlotDeprive: + + private var needsDeleteUnregisteredShip: Bool { + + switch apiResponse.api.endpoint { + + case .ship3, .getShip, .shipDeck, .powerup, .slotDeprive: + return false + + case .ship2: + // 特殊任務のクリア時にship2がapi_shipid付きでリクエストされ、その艦娘のデータしかない時があるため + + return !apiResponse.parameter["api_shipid"].valid + default: + return true + } } + private var store: ServerDataStore? { + return configuration.editorStore as? ServerDataStore } func beginRegister(_ ship: Ship) { + ship.sally_area = nil } + func handleExtraValue(_ value: JSON, forKey key: String, to ship: Ship) -> Bool { + // 取得後破棄した装備のデータを削除するため保有IDを保存 if key == "api_id" { - guard let id = value.int else { return false } + + guard let id = value.int else { + + return false + } + registerIds.append(id) + return false } if key == "api_ship_id" { - guard let masterId = value.int else { return false } + + guard let masterId = value.int else { + + return false + } + + if ship.ship_id == masterId { + + return true + } + setMaster(masterId, to: ship) + return true } + if key == "api_exp" { - guard let exp = value[0].int else { return false } + + guard let exp = value[0].int else { + + return false + } + + if ship.exp == exp { + + return true + } + ship.exp = exp + return true } + if key == "api_slot" { + setSlot(value, to: ship) + return false } + if key == "api_slot_ex" { - guard let ex = value.int else { return false } + + guard let ex = value.int else { + + ship.extraItem = nil + + return false + } + + if ship.slot_ex == ex { + + return true + } + setExtraSlot(ex, to: ship) - return false + + ship.slot_ex = ex + + return true } return false } + func finishOperating() { - if !isDeleteNotExist { return } + + if !needsDeleteUnregisteredShip { + + return + } + store?.ships(exclude: registerIds).forEach { store?.delete($0) } } private func setMaster(_ masterId: Int, to ship: Ship) { - if ship.ship_id == masterId { return } + guard let mShip = masterShips.binarySearch(comparator: { $0.id ==? masterId }), - let masterShip = store?.object(with: mShip.objectID) as? MasterShip - else { return print("Can not convert to current moc object masterShip") } + let masterShip = store?.exchange(mShip) else { + + Logger.shared.log("Can not convert to current moc object masterShip") + + return + } + ship.master_ship = masterShip ship.ship_id = masterId } private func setSlot(_ slotItems: JSON, to ship: Ship) { - guard let converSlotItems = slotItems.arrayObject as? [Int], - let store = store - else { return } - let newItems: [SlotItem] = - converSlotItems.flatMap { item in - if item == 0 || item == -1 { return nil } + + guard let convertedSlotItems = slotItems.arrayObject as? [Int] else { + + return + } + guard let store = store else { + + return + } + + let newItems: [SlotItem] = convertedSlotItems + .filter { $0 != 0 && $0 != -1 } + .compactMap { item in + guard let found = self.slotItems.binarySearch(comparator: { $0.id ==? item }), - let slotItem = store.object(with: found.objectID) as? SlotItem - else { - let maxV = converSlotItems.last + let slotItem = store.exchange(found) else { + + let maxV = convertedSlotItems.last if maxV != nil, maxV! < item { - #if DEBUG - print("item is maybe unregistered, so it is new ship's equipment.") - #endif + + Debug.print("item is maybe unregistered, so it is new ship's equipment.") + return nil } - print("Can not convert to current moc object slotItem") + Logger.shared.log("Can not convert to current moc object slotItem") + return nil } + return slotItem } + ship.equippedItem = NSOrderedSet(array: newItems) } + private func setExtraSlot(_ exSlotItem: Int, to ship: Ship) { - guard exSlotItem != -1, - exSlotItem != 0 - else { return } + + guard exSlotItem != -1, exSlotItem != 0 else { + + ship.extraItem = nil + + return + } guard let found = slotItems.binarySearch(comparator: { $0.id ==? exSlotItem }), - let ex = store?.object(with: found.objectID) as? SlotItem - else { return print("Can not convert to current moc object") } + let ex = store?.exchange(found) else { + + Logger.shared.log("Can not convert to current moc object") + + return + } + ship.extraItem = ex } }