From dc85d0179e89612e96d5b79ed7dc387e5f260acb Mon Sep 17 00:00:00 2001 From: Aldin Duraki Date: Sun, 17 May 2020 21:40:41 +0200 Subject: [PATCH] * Impl. RoundCalculationService * Impl. SnapshotModel * Impl. DataTransfer for SnapshotModel * Impl. PlayerMoveType * Changed DataService functionality --- GoldWars/GoldWars.xcodeproj/project.pbxproj | 6 +- .../GoldWars/Components/TimerComponent.swift | 4 +- GoldWars/GoldWars/DataService.swift | 29 ++++++- GoldWars/GoldWars/Entities/Base.swift | 11 +-- .../GoldWars/Entities/EntityManager.swift | 14 +++ GoldWars/GoldWars/Enums/PlayerMoveType.swift | 13 +++ GoldWars/GoldWars/MatchmakingHelper.swift | 5 ++ GoldWars/GoldWars/MultiplayerNetwork.swift | 6 ++ .../GoldWars/RoundCalculatorService.swift | 86 ++++++++++++++++--- GoldWars/GoldWars/Scenes/GameScene.swift | 4 +- 10 files changed, 154 insertions(+), 24 deletions(-) create mode 100644 GoldWars/GoldWars/Enums/PlayerMoveType.swift diff --git a/GoldWars/GoldWars.xcodeproj/project.pbxproj b/GoldWars/GoldWars.xcodeproj/project.pbxproj index 6e22439..b532d49 100644 --- a/GoldWars/GoldWars.xcodeproj/project.pbxproj +++ b/GoldWars/GoldWars.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 2086465C2461B66200817C23 /* TimerComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2086465B2461B66200817C23 /* TimerComponent.swift */; }; 3EBD242C245D8044003CECE7 /* GameCenterHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EBD242B245D8044003CECE7 /* GameCenterHelper.swift */; }; 3EBD242E245D9332003CECE7 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EBD242D245D9332003CECE7 /* Team.swift */; }; + 3F745DF0246F48FC00CE7375 /* PlayerMoveType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F745DEF246F48FC00CE7375 /* PlayerMoveType.swift */; }; 3FE19DB3246C690B004827AB /* RoundSimulatorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FE19DB2246C690B004827AB /* RoundSimulatorService.swift */; }; 3FE19DB5246C7A22004827AB /* RoundCalculatorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FE19DB4246C7A22004827AB /* RoundCalculatorService.swift */; }; 9E04AFAF245E2B73002D5CFC /* AttackActionComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04AFAE245E2B73002D5CFC /* AttackActionComponent.swift */; }; @@ -86,6 +87,7 @@ 2086465B2461B66200817C23 /* TimerComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerComponent.swift; sourceTree = ""; }; 3EBD242B245D8044003CECE7 /* GameCenterHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameCenterHelper.swift; sourceTree = ""; }; 3EBD242D245D9332003CECE7 /* Team.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Team.swift; sourceTree = ""; }; + 3F745DEF246F48FC00CE7375 /* PlayerMoveType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerMoveType.swift; sourceTree = ""; }; 3FE19DB2246C690B004827AB /* RoundSimulatorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundSimulatorService.swift; sourceTree = ""; }; 3FE19DB4246C7A22004827AB /* RoundCalculatorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundCalculatorService.swift; sourceTree = ""; }; 9E04AFAE245E2B73002D5CFC /* AttackActionComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttackActionComponent.swift; sourceTree = ""; }; @@ -101,7 +103,7 @@ 9E78ACBD245CC9C000526FF7 /* AtkBoostSkillComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtkBoostSkillComponent.swift; sourceTree = ""; }; 9E78ACC1245CC9EE00526FF7 /* DefBoostSkillComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefBoostSkillComponent.swift; sourceTree = ""; }; 9E78ACC3245CCA3600526FF7 /* SpySkillComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpySkillComponent.swift; sourceTree = ""; }; - 9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBaseComponent.swift; sourceTree = ""; }; + 9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBaseComponent.swift; sourceTree = ""; wrapsLines = 1; }; 9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNode.swift; sourceTree = ""; }; 9EA3ABEC245C8143006BC61D /* ModalBackgroundComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalBackgroundComponent.swift; sourceTree = ""; }; 9EA3ABEE245C834B006BC61D /* ModalContentComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalContentComponent.swift; sourceTree = ""; }; @@ -259,6 +261,7 @@ 11738A3A24508F68004426F1 /* Unit.swift */, 9EC86BA5245C8AD000796EF3 /* ModalType.swift */, 3EBD242D245D9332003CECE7 /* Team.swift */, + 3F745DEF246F48FC00CE7375 /* PlayerMoveType.swift */, ); path = Enums; sourceTree = ""; @@ -422,6 +425,7 @@ 9EA3ABED245C8143006BC61D /* ModalBackgroundComponent.swift in Sources */, C064E9A8246C0EA50022B228 /* LabelNode.swift in Sources */, 3EBD242C245D8044003CECE7 /* GameCenterHelper.swift in Sources */, + 3F745DF0246F48FC00CE7375 /* PlayerMoveType.swift in Sources */, AB1D759C245DD18100671525 /* MapProtocol.swift in Sources */, AB1D75A0245DEC0500671525 /* MapFactory.swift in Sources */, AB1D759D245DD18100671525 /* TwoPlayerDefaultTestMap.swift in Sources */, diff --git a/GoldWars/GoldWars/Components/TimerComponent.swift b/GoldWars/GoldWars/Components/TimerComponent.swift index 5ad2695..0b61efc 100644 --- a/GoldWars/GoldWars/Components/TimerComponent.swift +++ b/GoldWars/GoldWars/Components/TimerComponent.swift @@ -14,7 +14,7 @@ class TimerComponent: GKComponent { var endTime :Date! var duration :Double - init(text: String, anchorPoint: CGPoint, duration: TimeInterval) { + init(text: String, anchorPoint: CGPoint, duration: TimeInterval) { self.labelNode = SKLabelNode(text: text) self.labelNode.fontColor = UIColor.black self.labelNode.fontSize = CGFloat(45) @@ -50,7 +50,7 @@ class TimerComponent: GKComponent { } if !RoundCalculatorServie.sharedInstance.isCalculating && DataService.sharedInstance.didReceiveAllData(){ - RoundCalculatorServie.sharedInstance.calculateRound() + RoundCalculatorServie.sharedInstance.calculateRound() } } } diff --git a/GoldWars/GoldWars/DataService.swift b/GoldWars/GoldWars/DataService.swift index 8d2d331..c093697 100644 --- a/GoldWars/GoldWars/DataService.swift +++ b/GoldWars/GoldWars/DataService.swift @@ -9,22 +9,41 @@ struct PlayerMove: Codable{ let fromBase: Int let toBase: Int - let unitCount: Int + var unitCount: Int } struct Host: Codable { let playerID: String } +struct SnapshotModel: Codable { + var baseEntites: [BaseEntityModel]? +} + +struct BaseEntityModel: Codable { + let baseId: Int + var unitCount: Int + var ownership: String +} + class DataService { static let sharedInstance = DataService() var localPlayerMoves: [PlayerMove] = [] var remotePlayerMoves: [String: [PlayerMove]] = [:] + var snapshotModel = SnapshotModel() var gameHost: Host? - + + // TODO: Update entries to merge equal moves func addMove(playerMove: PlayerMove) { - self.localPlayerMoves.append(playerMove) + var equalMove = localPlayerMoves.filter { (ele) -> Bool in + ele.fromBase == playerMove.fromBase && ele.toBase == playerMove.toBase + } + if equalMove.count == 1 { + equalMove[0].unitCount = Int(equalMove[0].unitCount) + Int(playerMove.unitCount) + } else { + self.localPlayerMoves.append(playerMove) + } } func addRemotePlayerMoves(playerID: String, playerMoves: [PlayerMove]) { @@ -38,4 +57,8 @@ class DataService { func setGameHost(host: Host) { self.gameHost = host } + + func safeSnapshot(snapshotModel: SnapshotModel) { + self.snapshotModel = snapshotModel + } } diff --git a/GoldWars/GoldWars/Entities/Base.swift b/GoldWars/GoldWars/Entities/Base.swift index 97b6f1b..ad05629 100644 --- a/GoldWars/GoldWars/Entities/Base.swift +++ b/GoldWars/GoldWars/Entities/Base.swift @@ -17,7 +17,7 @@ class Base: GKEntity{ var changeOwnership: Bool var ownershipPlayer: GKPlayer? var baseID: Int - + init(position: CGPoint, player: GKPlayer! = nil, team: Team! = nil) { self.unitCount = 0 self.adjacencyList = [Base]() @@ -34,16 +34,17 @@ class Base: GKEntity{ } } - func attackBase(base: Base, units:Int) -> [GKEntity]{ + func doPlayerMoveTypeToBase(base: Base, playerMoveType: PlayerMoveType, units: Int) -> [GKEntity]{ base.changeOwnership = true base.ownershipPlayer = self.ownershipPlayer self.unitCount -= units base.unitCount += units - DataService.sharedInstance.addMove(playerMove: PlayerMove(fromBase: self.baseID, toBase: base.baseID, unitCount: units)) + DataService.sharedInstance.addMove(playerMove: PlayerMove(fromBase: self.baseID, + toBase: base.baseID, + unitCount: units * playerMoveType.rawValue)) return [self, base] } - - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/GoldWars/GoldWars/Entities/EntityManager.swift b/GoldWars/GoldWars/Entities/EntityManager.swift index 2f41dcf..a2ddeaa 100644 --- a/GoldWars/GoldWars/Entities/EntityManager.swift +++ b/GoldWars/GoldWars/Entities/EntityManager.swift @@ -181,4 +181,18 @@ class EntityManager { func getHUD() -> GKEntity? { return entities.filter{$0 is HUD}[0] } + + + + func getSnapshotModel() -> SnapshotModel { + let bases = entities.filter{$0 is Base} + var snapBase: [BaseEntityModel] = [] + + for entity in bases { + let base = entity as! Base + snapBase.append(BaseEntityModel(baseId: base.baseID, unitCount: base.unitCount, ownership: base.ownershipPlayer!.displayName)) + } + + return SnapshotModel(baseEntites: snapBase) + } } diff --git a/GoldWars/GoldWars/Enums/PlayerMoveType.swift b/GoldWars/GoldWars/Enums/PlayerMoveType.swift new file mode 100644 index 0000000..2f1bdd6 --- /dev/null +++ b/GoldWars/GoldWars/Enums/PlayerMoveType.swift @@ -0,0 +1,13 @@ +// +// PlayerMoveType.swift +// GoldWars +// +// Created by Aldin Duraki on 16.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +enum PlayerMoveType: Int, Codable{ + case AtkMove = 1 + case TxnMove = -1 +} + diff --git a/GoldWars/GoldWars/MatchmakingHelper.swift b/GoldWars/GoldWars/MatchmakingHelper.swift index d343e40..ca0ee49 100644 --- a/GoldWars/GoldWars/MatchmakingHelper.swift +++ b/GoldWars/GoldWars/MatchmakingHelper.swift @@ -116,6 +116,11 @@ class MatchmakingHelper: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDe if let message = try? jsonDecoder.decode(Host.self, from: data) { DataService.sharedInstance.gameHost = message } + + if let snapshotModel = try? jsonDecoder.decode(SnapshotModel.self, from: data) { + DataService.sharedInstance.snapshotModel = snapshotModel + } + MultiplayerNetwork.sharedInstance.isSending = false } diff --git a/GoldWars/GoldWars/MultiplayerNetwork.swift b/GoldWars/GoldWars/MultiplayerNetwork.swift index 36503ad..1511377 100644 --- a/GoldWars/GoldWars/MultiplayerNetwork.swift +++ b/GoldWars/GoldWars/MultiplayerNetwork.swift @@ -57,5 +57,11 @@ class MultiplayerNetwork{ let encoded = (try? encoder.encode(DataService.sharedInstance.gameHost))! sendData(data: encoded) } + + func sendSnapshotModelToPlayers() { + let encoder = JSONEncoder() + let encoded = (try? encoder.encode(DataService.sharedInstance.snapshotModel))! + sendData(data: encoded) + } } diff --git a/GoldWars/GoldWars/RoundCalculatorService.swift b/GoldWars/GoldWars/RoundCalculatorService.swift index 2032a93..fd300b7 100644 --- a/GoldWars/GoldWars/RoundCalculatorService.swift +++ b/GoldWars/GoldWars/RoundCalculatorService.swift @@ -11,15 +11,19 @@ import GameKit import os class RoundCalculatorServie { - static let sharedInstance = RoundCalculatorServie() - - var allPlayerMoves: [String: [PlayerMove]] = [:] - var baseSpecificMove: [Int: [(String, PlayerMove)]] = [:] var isCalculating = false + var allPlayerMoves: [String: [PlayerMove]] = [:] + var baseSpecificMoves: [Int: [String: PlayerMove]] = [:] + func calculateRound() { + os_log("Started calculating Round", log: OSLog.default, type: .info) + let startTime = CFAbsoluteTimeGetCurrent() isCalculating = true + let currentSnapshotModel = DataService.sharedInstance.snapshotModel.baseEntites + + // TODO: smarter way? for entry in DataService.sharedInstance.remotePlayerMoves { addPlayerMove(playerID: entry.key, playerMoves: entry.value) } @@ -27,22 +31,80 @@ class RoundCalculatorServie { for entry in allPlayerMoves { for move in entry.value { - addFiltedMove(playerName: entry.key, playerMove: move) + mapPlayerMoveToAttackedBase(playerName: entry.key, playerMove: move) } } - // berechnen nach minimal substraction + // TODO-END: - - print(baseSpecificMove) - isCalculating = false - // sende an alle anderen spieler die moves + for (key, value) in baseSpecificMoves { + let baseId = key + var playerMovesByBase = value + + let targetBase = currentSnapshotModel?.filter { $0.baseId == baseId }[0] + let possiblyOwnershipMoves = playerMovesByBase.filter { $0.key == targetBase?.ownership} + + // spieler verschiebt einheiten beim schieben + for (playerName, playerMove) in possiblyOwnershipMoves { + for var base in currentSnapshotModel! { + if base.baseId == playerMove.fromBase { + base.unitCount -= playerMove.unitCount + } + if base.baseId == playerMove.toBase { + base.unitCount += playerMove.unitCount + } + } + playerMovesByBase.removeValue(forKey: playerName) + } + + for (playerName, playerMove) in playerMovesByBase { + for var base in currentSnapshotModel! { + if base.baseId == playerMove.fromBase { + base.unitCount -= playerMove.unitCount + } + } + } + + + let sorted = playerMovesByBase.sorted { (e1: (key: String, value: PlayerMove), e2: (key: String, value: PlayerMove)) -> Bool in + e1.value.unitCount > e2.value.unitCount + } + + var max = sorted[0] + let secMax = sorted[1] + max.value.unitCount -= secMax.value.unitCount + + for var base in currentSnapshotModel! { + if base.baseId == max.value.toBase { + base.unitCount -= max.value.unitCount + base.ownership = max.key + } + } + + baseSpecificMoves.removeValue(forKey: baseId) + } + + MultiplayerNetwork.sharedInstance.sendSnapshotModelToPlayers() + let calcTime = CFAbsoluteTimeGetCurrent() - startTime + os_log("Finished calculating Round in %{calcTimer}", log: OSLog.default, type: .info, calcTime) } func addPlayerMove(playerID: String, playerMoves: [PlayerMove]) { self.allPlayerMoves[playerID] = playerMoves } - func addFiltedMove(playerName: String, playerMove: PlayerMove) { - self.baseSpecificMove.merge([playerMove.toBase : [(playerName, playerMove)]], uniquingKeysWith: +) + func mapPlayerMoveToAttackedBase(playerName: String, playerMove: PlayerMove) { + if self.baseSpecificMoves.keys.contains(playerMove.toBase) { + var playerMovesForSameBase = self.baseSpecificMoves[playerMove.toBase]! + if playerMovesForSameBase.keys.contains(playerName) { + playerMovesForSameBase[playerName] = playerMove + } + } else { + self.baseSpecificMoves[playerMove.toBase] = [playerName: playerMove] + } } + + func resolvePlayerMove(playerMove: PlayerMove, unitCount: Int, ownership: String?, resolveType: String) { + //outsource playermoves || tnx, remove, add(with calc) + } + } diff --git a/GoldWars/GoldWars/Scenes/GameScene.swift b/GoldWars/GoldWars/Scenes/GameScene.swift index dae1566..3a5a5c8 100644 --- a/GoldWars/GoldWars/Scenes/GameScene.swift +++ b/GoldWars/GoldWars/Scenes/GameScene.swift @@ -26,6 +26,7 @@ class GameScene: SKScene{ func initMap() { MapFactory(scene: self, entityManager: self.entityManager).loadMap(playerCount: 2) + DataService.sharedInstance.safeSnapshot(snapshotModel: entityManager.getSnapshotModel()) } override func touchesEnded(_ touches: Set, with event: UIEvent?) { @@ -49,12 +50,13 @@ class GameScene: SKScene{ base: currentDraggedBase!, anchorPoint: CGPoint(x: self.size.width / 2 , y: self.size.height / 2), entityManager: entityManager, gameScene: self)) - entityManager.update((currentDraggedBase?.attackBase(base: base, units: 100))!) + entityManager.update((currentDraggedBase?.doPlayerMoveTypeToBase(base: base, playerMoveType: PlayerMoveType.AtkMove, units: 100))!) }else { entityManager.add(Modal(modaltype: .BaseAttack, base: currentDraggedBase!, anchorPoint: CGPoint(x: self.size.width / 2 , y: self.size.height / 2), entityManager: entityManager, gameScene: self)) + entityManager.update((currentDraggedBase?.doPlayerMoveTypeToBase(base: base,playerMoveType: PlayerMoveType.TxnMove, units: -100))!) } }