software-projekt-2-gold-wars/GoldWars/GoldWars/MatchmakingHelper.swift
127-Z3R0 e447a37757 * Add 3 Instances for each Scene
* Refactor in Code that the right instances is called
* Probs to Aldin und nicht an Niko, der nur im Bett liegt
2020-05-23 18:36:59 +02:00

217 lines
7.3 KiB
Swift

//
// MatchmakingHelper.swift
// GoldWars
//
// Created by Chauntalle Schüle, Ömer Özel, Eray Kör on 03.05.20.
// Copyright © 2020 SP2. All rights reserved.
//
import GameKit
protocol GameKitHelperDelegate {
func matchStarted()
func matchEnded()
func matchReceivedData(match: GKMatch, data: NSData,
fromPlayer player: String)
}
/*
Diese Klasse wird für das Matchmaking über das Gamecenter gebraucht
@param: delegate: erhält alle Multiplayerevents
@param: mpMatch: repräsentiert das Netzwerk, alle Mitspieler besitzen ein gemeinsames Spiel
@param: viewController: ist nicht der ViewController des Gamecenters, sondern des Spiels
@param: mpMatchStarted: gibt an, ob ein Match schon gestartet wurde
@param: isServer: gibt an, ob der local player, als der Server fungiert
@param: spieler1: ist immer der Spieler, der der Server ist
@param: spieler2: ist immer der Spieler, der der Client ist
@param: sharedInstance: ist eine geteilte Instanz für alle Spieler
*/
class MatchmakingHelper: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDelegate {
var delegate: GameKitHelperDelegate?
var mpMatch: GKMatch?
var viewController: UIViewController?
var mpMatchStarted: Bool
var isServer: Bool
var spieler1: GKPlayer?
var nameSpieler1 = ""
var menusc: MenuScene?
let localPlayer: GKLocalPlayer = GKLocalPlayer.local
var entityManager = EntityManager.gameEMInstance
static let sharedInstance = MatchmakingHelper()
static var isAuthenticated: Bool{
return GKLocalPlayer.local.isAuthenticated
}
override init() {
mpMatchStarted = false
isServer = false
super.init()
}
/*
Diese Methode wechselt von der MenuScene zum GameCenter ViewController. Die Spieler werden hier gesucht und gematcht. Mit minplayers/maxplayers kann bestimmt werden, wie viele Spieler insgesamt zusammen miteinander spielen.
*/
func presentMatchmaker(scene: MenuScene) {
menusc = scene
guard GKLocalPlayer.local.isAuthenticated else {
return
}
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
request.inviteMessage = "Willst du GoldWars spielen?"
let matchmakerVC = GKMatchmakerViewController.init(matchRequest: request)
matchmakerVC!.matchmakerDelegate = self
viewController?.present(matchmakerVC!, animated: true, completion: nil)
}
/*
Der User hat die Verbindung mit "Abbrechen" unterbrochen. GameCenter MatchMaking wird beendet.
*/
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
viewController.dismiss(animated: true, completion: nil)
delegate?.matchEnded()
}
/*
Wenn GameCenter kein match erstellen kann, wird der viewcontroller dismissed.
*/
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
viewController.dismiss(animated: true, completion: nil)
print("Error finding match", error.localizedDescription)
delegate?.matchEnded()
}
/*
Gamecenter hat erfolgreich ein Match gefunden, das Spiel kann gestartet werden.
expectedPlayerCount: Die verbleibende Anzahl von Spielern, die sich noch nicht mit dem Spiel verbunden haben
z.B 0 gibt an, dass keine weiteren Spieler benötigt werden um das Match zu starten
*/
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
viewController.dismiss(animated: true, completion: nil)
mpMatch = match
match.delegate = self
if !mpMatchStarted && match.expectedPlayerCount == 0 {
startMatch()
}
}
/*
Vom match erhaltene Spielerdaten
*/
func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) {
if mpMatch != match { return }
let jsonDecoder = JSONDecoder()
if let playerMoves = try? jsonDecoder.decode([PlayerMove].self, from: data) {
DataService.sharedInstance.addRemotePlayerMoves(playerName: player.displayName, playerMoves: playerMoves)
}
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
entityManager.updateSnapshotModel(snapshotModel: snapshotModel)
entityManager.getTimer().startWithDuration(duration: 31)
}
if let mapModel = try? jsonDecoder.decode(MapGenerationModel.self, from: data) {
DataService.sharedInstance.setMapModel(model: mapModel)
}
MultiplayerNetwork.sharedInstance.isSending = false
}
/*
Verbindung/Matchmaking ist fehlgeschlagen
*/
private func match(match: GKMatch!, didFailWithError error: NSError!) {
if mpMatch != match {
return
}
mpMatchStarted = false
delegate?.matchEnded()
}
/*
Wird beim ändern des States/Zustands des Spielers aufgerufen udn gibt dessen Zustand zurück.
*/
func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState) {
if mpMatch != match {
return
}
switch (state) {
case GKPlayerConnectionState.connected:
if (!mpMatchStarted && match.expectedPlayerCount == 0) {
startMatch()
}
case GKPlayerConnectionState.disconnected:
mpMatchStarted = false
delegate?.matchEnded()
default:
delegate?.matchEnded()
}
}
/*
Ein Spieler wird als Host für das Match gewählt. Dieser ist Spieler 1. Im Anschluss wird die GameScene geladen.
*/
func startMatch() {
mpMatch!.chooseBestHostingPlayer(completionHandler: {
(player) in
self.mpMatchStarted = true
if player == GKLocalPlayer.local {
self.isServer = true
self.spieler1 = player
self.nameSpieler1 = self.spieler1!.displayName
DataService.sharedInstance.setGameHost(host: Host(playerName: player!.displayName))
} else {
self.isServer = false
}
self.delegate?.matchStarted()
let scene = GameScene(size: self.menusc!.size)
self.entityManager.setScene(scene: scene)
self.menusc!.loadScene(scene: scene)
MultiplayerNetwork.sharedInstance.sendHostIdentifier()
})
}
func getGKPlayerByUsername(displayName: String) -> GKPlayer? {
let nilGK : GKPlayer? = nil
if GKLocalPlayer.local.displayName == displayName {
return GKLocalPlayer.local
}
for player in mpMatch!.players {
if player.displayName == displayName {
return player
}
}
return nilGK
}
/*
Trennt die Verbindung vom Match
*/
func disconnect() {
if mpMatch != nil {
mpMatch?.disconnect()
}
}
}