import Cocoa
enum ChangeHenseiType: Int {
+
case append
+
case replace
+
case remove
+
case removeAllWithoutFlagship
}
extension Notification.Name {
+
static let HenseiDidChange = Notification.Name("com.masakih.KCD.Notification.HenseiDidChange")
}
-class HenseiDidChangeUserInfo: NSObject {
+final class HenseiDidChangeUserInfo: NSObject {
+
let type: ChangeHenseiType
let fleetNumber: Int
let replacePosition: Int?
let replaceShipID: Int?
- var objcType: Int { return type.rawValue }
- var objcReplaceFleetNumbner: NSNumber? { return replaceFleetNumber as NSNumber?? ?? nil }
- var objcReplacePosition: NSNumber? { return replacePosition as NSNumber?? ?? nil }
- var objcReplaceShipID: NSNumber? { return replaceShipID as NSNumber?? ?? nil }
-
required init(type: ChangeHenseiType,
fleetNumber: Int,
position: Int,
replaceFleetNumber: Int? = nil,
replacePosition: Int? = nil,
replaceShipID: Int? = nil) {
+
self.type = type
self.fleetNumber = fleetNumber
self.position = position
self.replaceFleetNumber = replaceFleetNumber
self.replacePosition = replacePosition
self.replaceShipID = replaceShipID
+
super.init()
}
}
-class ChangeHenseiCommand: JSONCommand {
+final class ChangeHenseiCommand: JSONCommand {
+
static let userInfoKey = "HenseiDidChangeUserInfoKey"
- override class func canExecuteAPI(_ api: String) -> Bool {
- if api == "/kcsapi/api_req_hensei/change" { return true }
- return false
+ override class func canExecuteAPI(_ api: API) -> Bool {
+
+ return api.endpoint == .change
}
// api_ship_id の値
// ship_id == -1 : remove.
// ship_id == -2 : remove all without flag ship.
override func execute() {
- guard let deckNumber = arguments["api_id"].flatMap({ Int($0) }),
- let shipId = arguments["api_ship_id"].flatMap({ Int($0) }),
- let shipIndex = arguments["api_ship_idx"].flatMap({ Int($0) })
- else { return print("parameter is wrong") }
+
+ guard let deckNumber = parameter["api_id"].int,
+ let shipId = parameter["api_ship_id"].int,
+ let shipIndex = parameter["api_ship_idx"].int else {
+
+ Logger.shared.log("parameter is wrong")
+
+ return
+ }
+
+ if shipId == -1 {
+
+ guard let shipId = removeShip(deckNumber: deckNumber, index: shipIndex) else {
+
+ return
+ }
+ notify(type: .remove, fleetNumber: deckNumber, position: shipIndex, shipID: shipId)
+
+ return
+ }
+
if shipId == -2 {
+
excludeShipsWithoutFlagShip(deckNumber: deckNumber)
notify(type: .removeAllWithoutFlagship)
+
return
}
+
+ guard case 0..<Deck.maxShipCount = shipIndex else {
+
+ return
+ }
+
let store = ServerDataStore.oneTimeEditor()
- let decks = store.decksSortedById()
- let shipIds = decks.flatMap { (deck) -> [Int] in
- return (0..<6).map {
- if let res = deck.value(forKey: "ship_\($0)") as? Int {
- return res
- }
- return -1
- }
+ guard let deck = store.sync(execute: { store.deck(by: deckNumber) }) else {
+
+ return
}
// すでに編成されているか? どこに?
- let alreadyInFleet = shipIds.contains(shipId)
- let index = alreadyInFleet ? shipIds.index(of: shipId) : nil
- let shipDeckNumber = index.map { $0 / 6 } ?? -1
- let shipDeckIndex = index.map { $0 % 6 } ?? -1
+ let (shipDeckNumber, shipDeckIndex) = position(of: shipId)
// 配置しようとする位置に今配置されている艦娘
- let currentIndex = (deckNumber - 1) * 6 + shipIndex
- guard 0..<shipIds.count ~= currentIndex
- else { return }
- let replaceShipId = shipIds[currentIndex]
+ let replaceShipId = store.sync { deck[shipIndex]?.id }
// 艦隊に配備
- guard 0..<decks.count ~= (deckNumber - 1)
- else { return }
- let deck = decks[deckNumber - 1]
- deck.setValue(shipId as NSNumber, forKey: "ship_\(shipIndex)")
+ store.sync { deck.setShip(id: shipId, for: shipIndex) }
// 入れ替え
- if alreadyInFleet,
- shipId != -1,
- 0..<decks.count ~= shipDeckNumber
- {
- let aDeck = decks[shipDeckNumber]
- aDeck.setValue(replaceShipId, forKey: "ship_\(shipDeckIndex)")
+ if shipDeckNumber != nil {
+
+ let shipDeck = store.sync { store.deck(by: shipDeckNumber!) }
+ store.sync { shipDeck?.setShip(id: replaceShipId ?? -1, for: shipDeckIndex) }
+ shipDeck.map { packFleet(store: store, deck: $0) }
}
- packFleet(store: store)
+ packFleet(store: store, deck: deck)
// Notify
- if alreadyInFleet && shipId == -1 {
- notify(type: .remove,
- fleetNumber: deckNumber,
- position: shipIndex,
- shipID: replaceShipId)
- } else if alreadyInFleet {
+ if shipDeckNumber != nil {
+
notify(type: .replace,
fleetNumber: deckNumber,
position: shipIndex,
shipID: shipId,
- replaceFleetNumber: shipDeckNumber + 1,
+ replaceFleetNumber: shipDeckNumber!,
replacePosition: shipDeckIndex,
replaceShipID: replaceShipId)
+
} else {
- notify(type: .append,
- fleetNumber: deckNumber,
- position: shipIndex,
- shipID: shipId)
+
+ notify(type: .append, fleetNumber: deckNumber, position: shipIndex, shipID: shipId)
+ }
+ }
+
+ private func position(of shipId: Int) -> (deckNumber: Int?, shipId: Int) {
+
+ let store = ServerDataStore.default
+
+ return store.sync {
+
+ store
+ .decksSortedById()
+ .lazy
+ .enumerated()
+ .map { (idx, deck) -> (Int, [Ship]) in (idx + 1, deck[0..<Deck.maxShipCount]) }
+ .filter { $0.1.contains { $0.id == shipId } }
+ .map { (deck, ships) in (deck, ships.index(where: { $0.id == shipId })!) }
+ .first ?? (nil, -1)
+ }
+ }
+
+ private func removeShip(deckNumber: Int, index: Int) -> Int? {
+
+ let store = ServerDataStore.oneTimeEditor()
+
+ guard let deck = store.sync(execute: { store.deck(by: deckNumber) }) else {
+
+ Logger.shared.log("Deck not found")
+
+ return nil
}
+
+ let shipId = store.sync { deck[index]?.id ?? -1 }
+ store.sync { deck.setShip(id: -1, for: index) }
+
+ packFleet(store: store, deck: deck)
+
+ return shipId
}
private func excludeShipsWithoutFlagShip(deckNumber: Int) {
+
let store = ServerDataStore.oneTimeEditor()
- guard let deck = store.deck(byId: deckNumber)
- else { return print("Deck not found") }
- (1..<6).forEach {
- deck.setValue(-1 as NSNumber, forKey: "ship_\($0)")
+ store.sync {
+ guard let deck = store.deck(by: deckNumber) else {
+
+ Logger.shared.log("Deck not found")
+
+ return
+ }
+
+ (1..<Deck.maxShipCount).forEach { deck.setShip(id: -1, for: $0) }
}
}
- private func packFleet(store: ServerDataStore) {
- store.decksSortedById()
- .forEach { (deck) in
- var needsPack = false
- (0..<6).forEach {
- let shipId = deck.value(forKey: "ship_\($0)") as? Int
- if (shipId == nil || shipId! == -1) && !needsPack {
- needsPack = true
- return
- }
- if needsPack {
- deck.setValue(shipId! as NSNumber, forKey: "ship_\($0 - 1)")
- if $0 == 5 {
- deck.setValue(-1 as NSNumber, forKey: "ship_5")
- }
- }
- }
+ private func packFleet(store: ServerDataStore, deck: Deck) {
+
+ func set(_ ships: [Ship], at index: Int, in deck: Deck) {
+
+ guard index < Deck.maxShipCount else {
+
+ return
+ }
+
+ deck.setShip(id: ships.first?.id ?? -1, for: index)
+
+ let newShips = ships.isEmpty ? [] : Array(ships[1...])
+
+ set(newShips, at: index + 1, in: deck)
}
+
+ store.sync { set(deck[0..<Deck.maxShipCount], at: 0, in: deck) }
}
private func notify(type: ChangeHenseiType,
replaceFleetNumber: Int? = nil,
replacePosition: Int? = nil,
replaceShipID: Int? = nil) {
+
let userInfo = HenseiDidChangeUserInfo(type: type,
fleetNumber: fleetNumber,
position: position,