From 1571a1e786ade64da1b3c2575eaad86a2f0d4a91 Mon Sep 17 00:00:00 2001 From: Aldin Duraki Date: Wed, 20 May 2020 00:11:49 +0200 Subject: [PATCH] * Impl. combined forces attack * Minor refactoring * Fixed component updates on updating entities from snapshot * Fixed mapping for incoming player moves --- .../GoldWars/Components/TimerComponent.swift | 4 +- .../GoldWars/Entities/EntityManager.swift | 49 ++++---- GoldWars/GoldWars/MatchmakingHelper.swift | 1 - GoldWars/GoldWars/MultiplayerNetwork.swift | 12 +- .../GoldWars/RoundCalculatorService.swift | 107 +++++++++--------- GoldWars/GoldWars/SoundManager.swift | 2 +- 6 files changed, 83 insertions(+), 92 deletions(-) diff --git a/GoldWars/GoldWars/Components/TimerComponent.swift b/GoldWars/GoldWars/Components/TimerComponent.swift index 596fd7b..0ed4e63 100644 --- a/GoldWars/GoldWars/Components/TimerComponent.swift +++ b/GoldWars/GoldWars/Components/TimerComponent.swift @@ -48,10 +48,10 @@ class TimerComponent: GKComponent { if !MultiplayerNetwork.sharedInstance.isSending { MultiplayerNetwork.sharedInstance.sendPlayerMoves(playerMoves: DataService.sharedInstance.localPlayerMoves) } - if !RoundCalculatorServie.sharedInstance.isCalculating + if !RoundCalculatorService.sharedInstance.isCalculating && DataService.sharedInstance.didReceiveAllData() && MatchmakingHelper.sharedInstance.isServer { - RoundCalculatorServie.sharedInstance.calculateRound() + RoundCalculatorService.sharedInstance.calculateRound() } } } diff --git a/GoldWars/GoldWars/Entities/EntityManager.swift b/GoldWars/GoldWars/Entities/EntityManager.swift index e17a264..7a49701 100644 --- a/GoldWars/GoldWars/Entities/EntityManager.swift +++ b/GoldWars/GoldWars/Entities/EntityManager.swift @@ -109,17 +109,17 @@ class EntityManager { let base = (entity as! Base) if base.changeOwnership { - if let component = entity.component(ofType: TeamComponent.self) { - component.player = entities[0].component(ofType: TeamComponent.self)!.player - component.team = entities[0].component(ofType: TeamComponent.self)!.team - } else { - base.addComponent(TeamComponent( - team: (entities[0] as! Base).component(ofType: TeamComponent.self)!.team, - player: (entities[0] as! Base).component(ofType: TeamComponent.self)!.player, - position: (base.component(ofType: DefaultBaseComponent.self)?.spriteNode.position)! - ) + //FIX-ME: Find a way to update the Component without deleting it upfront + //TODO: outsource component handling to a generic function + base.removeComponent(ofType: TeamComponent.self) + base.addComponent(TeamComponent( + team: (entities[0] as! Base).component(ofType: TeamComponent.self)!.team, + player: (entities[0] as! Base).component(ofType: TeamComponent.self)!.player, + position: (base.component(ofType: DefaultBaseComponent.self)?.spriteNode.position)! ) - scene.addChild(base.component(ofType: TeamComponent.self)!.fire) + ) + if let fire = entity.component(ofType: TeamComponent.self)?.fire{ + scene.addChild(fire) } base.changeOwnership = false } @@ -131,35 +131,28 @@ class EntityManager { for entity in bases{ let base = entity as! Base let snapBase = self.getSnapshotBaseById(baseId: base.baseID, snapshotModel: snapshotModel) - print("in updateSnap -> Entity \(base)") - print("in updateSnap -> snapBase \(snapBase)") var getOwnerBySnapBase: GKPlayer? = nil base.unitCount = snapBase.unitCount - + if snapBase.ownership != nil { getOwnerBySnapBase = MatchmakingHelper.sharedInstance.getGKPlayerByUsername(displayName: snapBase.ownership!) } if getOwnerBySnapBase != nil { base.changeOwnership = true base.ownershipPlayer = getOwnerBySnapBase - if let component = entity.component(ofType: TeamComponent.self) { - component.player = getOwnerBySnapBase! - component.team = getTeamByPlayer(playerName: snapBase.ownership!) - } else { - entity.addComponent(TeamComponent( - team: getTeamByPlayer(playerName: snapBase.ownership!), - player: getOwnerBySnapBase!, - position: (entity.component(ofType: DefaultBaseComponent.self)?.spriteNode.position)! - ) + //FIX-ME: Find a way to update the Component without deleting it upfront + //TODO: outsource component handling to a generic function + entity.removeComponent(ofType: TeamComponent.self) + entity.addComponent(TeamComponent( + team: getTeamByPlayer(playerName: snapBase.ownership!), + player: getOwnerBySnapBase!, + position: (entity.component(ofType: DefaultBaseComponent.self)?.spriteNode.position)! ) - if let fire = entity.component(ofType: TeamComponent.self)?.fire{ - scene.addChild(fire) - } + ) + if let fire = entity.component(ofType: TeamComponent.self)?.fire{ + scene.addChild(fire) } - } - - print("nach updateSnap -> Entity \(base)") } } diff --git a/GoldWars/GoldWars/MatchmakingHelper.swift b/GoldWars/GoldWars/MatchmakingHelper.swift index dbdc066..a695d39 100644 --- a/GoldWars/GoldWars/MatchmakingHelper.swift +++ b/GoldWars/GoldWars/MatchmakingHelper.swift @@ -118,7 +118,6 @@ class MatchmakingHelper: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDe } if let snapshotModel = try? jsonDecoder.decode(SnapshotModel.self, from: data) { - print("received data package -> \(snapshotModel)") DataService.sharedInstance.snapshotModel = snapshotModel EntityManager.sharedInstance.updateSnapshotModel(snapshotModel: snapshotModel) } diff --git a/GoldWars/GoldWars/MultiplayerNetwork.swift b/GoldWars/GoldWars/MultiplayerNetwork.swift index 8b470bd..32926d2 100644 --- a/GoldWars/GoldWars/MultiplayerNetwork.swift +++ b/GoldWars/GoldWars/MultiplayerNetwork.swift @@ -12,6 +12,7 @@ import GameKit class MultiplayerNetwork{ static let sharedInstance = MultiplayerNetwork() + var isSending = false func sendData(data: Data) { @@ -20,25 +21,20 @@ class MultiplayerNetwork{ do { try multiplayerMatch.sendData(toAllPlayers: data, with: .reliable) } catch { - print("Tim war am Werk") + //TODO: Add logging } } } func sendDataToHost(data: Data) { let mmHelper = MatchmakingHelper.sharedInstance - for player in mmHelper.mpMatch!.players { - print(player.displayName) - } - print(DataService.sharedInstance.gameHost!.playerName) - let hostGKPlayer = MatchmakingHelper.sharedInstance.mpMatch?.players.filter{ $0.displayName == DataService.sharedInstance.gameHost!.playerName}[0] if let multiplayerMatch = mmHelper.mpMatch{ do { try multiplayerMatch.send(data, to: [hostGKPlayer!], dataMode: .reliable) } catch { - print("Tim war mal wieder am Werk der Krasse") + //TODO: Add logging } } } @@ -59,10 +55,8 @@ class MultiplayerNetwork{ } func sendSnapshotModelToPlayers() { - print("sending snapshot -> \(DataService.sharedInstance.snapshotModel)") let encoder = JSONEncoder() let encoded = (try? encoder.encode(DataService.sharedInstance.snapshotModel))! - print("sending package -> \(encoded)") sendData(data: encoded) } diff --git a/GoldWars/GoldWars/RoundCalculatorService.swift b/GoldWars/GoldWars/RoundCalculatorService.swift index 72e31a2..4b92575 100644 --- a/GoldWars/GoldWars/RoundCalculatorService.swift +++ b/GoldWars/GoldWars/RoundCalculatorService.swift @@ -6,93 +6,97 @@ // Copyright © 2020 SP2. All rights reserved. // -import Foundation import GameKit import os -class RoundCalculatorServie { - static let sharedInstance = RoundCalculatorServie() - var isCalculating = false +class RoundCalculatorService { + static let sharedInstance = RoundCalculatorService() + static let LOG = OSLog.init(subsystem: "Round Calculator", category: "RoundCalculatorService") var allPlayerMoves: [String: [PlayerMove]] = [:] - var baseSpecificMoves: [Int: [String: PlayerMove]] = [:] + var baseSpecificMoves: [Int: [String: [PlayerMove]]] = [:] + + var isCalculating = false func calculateRound() { - os_log("Started calculating Round", log: OSLog.default, type: .info) - let startTime = CFAbsoluteTimeGetCurrent() + os_log("Started calculating Round", log: RoundCalculatorService.LOG, type: .info) isCalculating = true + let currentSnapshotModel = DataService.sharedInstance.snapshotModel - var currentSnapshotModel = DataService.sharedInstance.snapshotModel - - // TODO: smarter way? - for entry in DataService.sharedInstance.remotePlayerMoves { - addPlayerMove(playerName: entry.key, playerMoves: entry.value) + for playerMove in DataService.sharedInstance.remotePlayerMoves { + addPlayerMove(playerName: playerMove.key, playerMoves: playerMove.value) } addPlayerMove(playerName: GKLocalPlayer.local.displayName, playerMoves: DataService.sharedInstance.localPlayerMoves) - for entry in allPlayerMoves { - for move in entry.value { - mapPlayerMoveToAttackedBase(playerName: entry.key, playerMove: move) + for playerMove in allPlayerMoves { + for move in playerMove.value { + mapPlayerMoveToAttackedBase(playerName: playerMove.key, playerMove: move) } } - // TODO-END: - - // TODO: Refactor -> O(n*3n^2) to maybe O(n*3n) - // We might not need to map and iterate over toBase + // TODO: Refactor to a less complex way for (key, value) in baseSpecificMoves { let baseId = key var playerMovesByBase = value let targetBase = currentSnapshotModel?.baseEntites.filter { $0.baseId == baseId }[0] let possiblyOwnershipMoves = playerMovesByBase.filter { $0.key == targetBase?.ownership} - - for (playerName, playerMove) in possiblyOwnershipMoves { - for base in currentSnapshotModel!.baseEntites { - if base.baseId == playerMove.fromBase { - base.unitCount -= playerMove.unitCount - } - if base.baseId == playerMove.toBase { - base.unitCount += playerMove.unitCount + + for (playerName, playerMoves) in possiblyOwnershipMoves { + for playerMove in playerMoves { + for base in currentSnapshotModel!.baseEntites { + if base.baseId == playerMove.fromBase { + base.unitCount -= playerMove.unitCount + } + if base.baseId == playerMove.toBase { + base.unitCount += playerMove.unitCount + } } } playerMovesByBase.removeValue(forKey: playerName) } - for (_, playerMove) in playerMovesByBase { - for base in currentSnapshotModel!.baseEntites { - if base.baseId == playerMove.fromBase { - base.unitCount -= playerMove.unitCount + for (_, playerMoves) in playerMovesByBase { + for playerMove in playerMoves { + for base in currentSnapshotModel!.baseEntites { + 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 combinePotentionalForces: [String: PlayerMove] = [:] + + for playerMoves in playerMovesByBase { + combinePotentionalForces[playerMoves.key] = PlayerMove(fromBase: playerMoves.value[0].fromBase, toBase: playerMoves.value[0].toBase, unitCount: 0) + for move in playerMoves.value { + combinePotentionalForces[playerMoves.key]!.unitCount += move.unitCount + } } - var max = sorted[0] - if sorted.count == 2 { - let secMax = sorted[1] - max.value.unitCount -= secMax.value.unitCount + let sortedPotentionalCombinedForces = combinePotentionalForces.sorted { $0.1.unitCount > $1.1.unitCount } + + var playerMoveWithMaxUnits = sortedPotentionalCombinedForces[0] + if playerMovesByBase.count >= 2 { + let playerMoveWithSecMaxUnits = sortedPotentionalCombinedForces[1] + playerMoveWithMaxUnits.value.unitCount -= playerMoveWithSecMaxUnits.value.unitCount } for base in currentSnapshotModel!.baseEntites { - if base.baseId == max.value.toBase { - base.unitCount += max.value.unitCount - if max.value.unitCount == 0 { + if base.baseId == playerMoveWithMaxUnits.value.toBase { + base.unitCount += playerMoveWithMaxUnits.value.unitCount + if playerMoveWithMaxUnits.value.unitCount == 0 { base.ownership = nil } else { - base.ownership = max.key + base.ownership = playerMoveWithMaxUnits.key } - - } - } + } + } baseSpecificMoves.removeValue(forKey: baseId) } MultiplayerNetwork.sharedInstance.sendSnapshotModelToPlayers() EntityManager.sharedInstance.updateSnapshotModel(snapshotModel: currentSnapshotModel!) - let calcTime = CFAbsoluteTimeGetCurrent() - startTime - os_log("Finished calculating Round in %@", log: OSLog.default, type: .info) + os_log("Finished calculating Round", log: RoundCalculatorService.LOG, type: .info) } func addPlayerMove(playerName: String, playerMoves: [PlayerMove]) { @@ -101,17 +105,18 @@ class RoundCalculatorServie { 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 + if (self.baseSpecificMoves[playerMove.toBase]?.keys.contains(playerName))!{ + self.baseSpecificMoves[playerMove.toBase]?[playerName]?.append(playerMove) + } else { + self.baseSpecificMoves[playerMove.toBase]?.merge([playerName: [playerMove]]){(current, _) in current} } } else { - self.baseSpecificMoves[playerMove.toBase] = [playerName: playerMove] + self.baseSpecificMoves[playerMove.toBase] = [playerName: [playerMove]] } } func resolvePlayerMove(playerMove: PlayerMove, unitCount: Int, ownership: String?, resolveType: String) { - //outsource playermoves || tnx, remove, add(with calc) + //TODO: outsource playermoves } } diff --git a/GoldWars/GoldWars/SoundManager.swift b/GoldWars/GoldWars/SoundManager.swift index 4f8f34d..b6cb5d4 100644 --- a/GoldWars/GoldWars/SoundManager.swift +++ b/GoldWars/GoldWars/SoundManager.swift @@ -23,7 +23,7 @@ class SoundManager { do { audioPlayer = try AVAudioPlayer(contentsOf: backgroundMainMenuAudio!) } catch { - print("Datei nicht gefunden!") + //TODO: Add logging } audioPlayer.numberOfLoops = -1 audioPlayer.prepareToPlay()