Marcel Schwarz
f852aae859
Calculate new EloData for both sides on serverside Report scores on both sides New Data type for sharing EloData
294 lines
12 KiB
Swift
294 lines
12 KiB
Swift
//
|
|
// GameCenter.swift
|
|
// GoldWars
|
|
//
|
|
// Created by Niko Jochim on 23.05.20.
|
|
// Copyright © 2020 SP2. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import GameKit
|
|
import os
|
|
|
|
struct RandomNumber: Codable {
|
|
let number: Int
|
|
init() {
|
|
number = Int.random(in: 0...999999)
|
|
}
|
|
}
|
|
|
|
struct State: Codable {
|
|
// 0 PlayerInit fertig
|
|
// 1 RemotePlayerInit fertig
|
|
// 2 Peer hat Map erhalten
|
|
// 3 Host hat Spiel gestartet
|
|
// 4 Peer hat verloren
|
|
// 5 Peer hat gewonnen
|
|
let state: Int
|
|
}
|
|
|
|
final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKGameCenterControllerDelegate ,GKMatchDelegate,GKLocalPlayerListener{
|
|
|
|
static var sharedInstance = GameCenterManager()
|
|
|
|
let LOG = OSLog.init(subsystem: "GameCenterManager", category: "GameCenterManager")
|
|
|
|
var viewController: UIViewController?
|
|
let localPlayer: GKLocalPlayer = GKLocalPlayer.local
|
|
var myMatch: GKMatch?
|
|
var isMatchStarted = false
|
|
var isServer = false
|
|
var hostingPlayer: GKPlayer?
|
|
var peerPlayer: GKPlayer?
|
|
var menusc: MenuScene?
|
|
var entityManager = EntityManager.gameEMInstance
|
|
var localPlayerRandomNumber: RandomNumber?
|
|
var initIsFinish = false
|
|
var gameEnded = false
|
|
var winner: String?
|
|
var gameScene: GameScene?
|
|
static var isAuthenticated: Bool {
|
|
return GKLocalPlayer.local.isAuthenticated
|
|
}
|
|
|
|
override init() {
|
|
super.init()
|
|
localPlayer.register(self)
|
|
authUser();
|
|
localPlayerRandomNumber = RandomNumber()
|
|
}
|
|
|
|
func reset() {
|
|
isMatchStarted = false
|
|
isServer = false
|
|
localPlayerRandomNumber = RandomNumber()
|
|
initIsFinish = false
|
|
gameEnded = false
|
|
winner = nil
|
|
gameScene = nil
|
|
}
|
|
|
|
func authUser() -> Void {
|
|
GKLocalPlayer.local.authenticateHandler = { gcAuthVC, error in
|
|
NotificationCenter.default
|
|
.post(name: .authenticationChanged, object: GKLocalPlayer.local.isAuthenticated)
|
|
if let vc = gcAuthVC {
|
|
self.viewController?.present(vc, animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
func presentMatchmaker() {
|
|
let request = GKMatchRequest()
|
|
request.minPlayers = 2
|
|
request.maxPlayers = 2
|
|
request.defaultNumberOfPlayers = 2
|
|
request.inviteMessage = "Willst du GoldWars spielen?"
|
|
let matchmakerVC = GKMatchmakerViewController.init(matchRequest: request)
|
|
matchmakerVC!.matchmakerDelegate = self
|
|
viewController?.present(matchmakerVC!, animated: true, completion: nil)
|
|
}
|
|
|
|
func presentGameCenter() {
|
|
let gameCenterController: GKGameCenterViewController = GKGameCenterViewController.init()
|
|
gameCenterController.gameCenterDelegate = self
|
|
gameCenterController.viewState = .achievements
|
|
viewController?.present(gameCenterController, animated: true, completion: nil)
|
|
}
|
|
|
|
func addAchievementProgress(identifier: String, increasePercentComplete: Double) {
|
|
GKAchievement.loadAchievements { (achievements: [GKAchievement]?, err: Error?) in
|
|
var achievementExists: Bool = false
|
|
achievements?.forEach({ (achievement: GKAchievement) in
|
|
print(achievement.identifier)
|
|
if achievement.identifier == identifier {
|
|
achievementExists = true
|
|
achievement.percentComplete += increasePercentComplete
|
|
achievement.showsCompletionBanner = true
|
|
GKAchievement.report([achievement]) { (error) in
|
|
print(error?.localizedDescription ?? "")
|
|
}
|
|
}
|
|
})
|
|
if !achievementExists {
|
|
let newAchievement: GKAchievement = GKAchievement.init(identifier: identifier)
|
|
newAchievement.showsCompletionBanner = true
|
|
newAchievement.percentComplete = increasePercentComplete
|
|
GKAchievement.report([newAchievement]) { (error) in
|
|
print(error?.localizedDescription ?? "")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) {
|
|
if myMatch != match { return }
|
|
let jsonDecoder = JSONDecoder()
|
|
if let randomNumberFromPeer = try? jsonDecoder.decode(RandomNumber.self, from: data) {
|
|
os_log("Random Number des anderen Spielers erhalten", log: LOG, type: .info)
|
|
if randomNumberFromPeer.number <= localPlayerRandomNumber!.number {
|
|
isServer = true
|
|
self.hostingPlayer = GKLocalPlayer.local
|
|
self.peerPlayer = player
|
|
os_log("Dieser Spieler wurde zum HostingPlayer gewählt", log: LOG, type: .info)
|
|
} else {
|
|
isServer = false
|
|
self.hostingPlayer = player
|
|
self.peerPlayer = GKLocalPlayer.local
|
|
os_log("Dieser Spieler wurde zum PeerPlayer gewählt", log: LOG, type: .info)
|
|
}
|
|
os_log("Setzen von Peer und Host abgeschlossen", log: LOG, type: .info)
|
|
sendStateToPeers(state: State(state: 0))
|
|
os_log("State 0 wurde an anderen Spieler gesendet", log: LOG, type: .info)
|
|
}
|
|
if let state = try? jsonDecoder.decode(State.self, from: data) {
|
|
switch state.state {
|
|
case 0:
|
|
os_log("State 0 erhalten", log: LOG, type: .info)
|
|
sendStateToPeers(state: State(state: 1))
|
|
case 1:
|
|
os_log("State 1 erhalten", log: LOG, type: .info)
|
|
|
|
if isServer {
|
|
os_log("Peer hat Player initialisiert", log: LOG, type: .info)
|
|
initAndSendMap()
|
|
}else {
|
|
os_log("Host hat Player initialisiert", log: LOG, type: .info)
|
|
}
|
|
case 2:
|
|
os_log("State 2 erhalten", log: LOG, type: .info)
|
|
sendStateToPeers(state: State(state: 3))
|
|
initIsFinish = true
|
|
os_log("Spiel startet", log: LOG, type: .info)
|
|
case 3:
|
|
os_log("State 3 erhalten", log: LOG, type: .info)
|
|
initIsFinish = true
|
|
os_log("Spiel startet", log: LOG, type: .info)
|
|
case 4:
|
|
os_log("State 4 erhalten, Peer hat verloren", log: LOG, type: .info)
|
|
winner = hostingPlayer?.displayName
|
|
gameEnded = true
|
|
case 5:
|
|
os_log("State 5 erhalten, Peer hat gewonnen", log: LOG, type: .info)
|
|
winner = peerPlayer?.displayName
|
|
gameEnded = true
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
if let roundData = try? jsonDecoder.decode(LocalRoundData.self, from: data) {
|
|
DataService.sharedInstance.addRemotePlayerMoves(playerName: player.displayName, localRoundData: roundData)
|
|
}
|
|
if let snapshotModel = try? jsonDecoder.decode(SnapshotModel.self, from: data) {
|
|
DataService.sharedInstance.snapshotModel = snapshotModel
|
|
RoundCalculatorService.sharedInstance.currentRound += 1
|
|
entityManager.getHUD()?.setCurrentRound(round: RoundCalculatorService.sharedInstance.currentRound)
|
|
entityManager.updateSnapshotModel(snapshotModel: snapshotModel)
|
|
entityManager.getHUD()?.startWithDuration()
|
|
}
|
|
if let mapModel = try? jsonDecoder.decode(MapGenerationModel.self, from: data) {
|
|
os_log("Peer hat Map erhalten", log: LOG, type: .info)
|
|
let scene = GameScene(size: self.menusc!.size)
|
|
EntityManager.gameEMInstance.setScene(scene: scene)
|
|
DataService.sharedInstance.setMapModel(model: mapModel)
|
|
os_log("Map model wurde gesetzt", log: LOG, type: .info)
|
|
GameCenterManager.sharedInstance.isMatchStarted = true
|
|
self.gameScene = scene
|
|
sendStateToPeers(state: State(state: 2))
|
|
os_log("State 2 wurde an Host gesendet", log: LOG, type: .info)
|
|
initIsFinish = true
|
|
os_log("Peer startet Spiel", log: LOG, type: .info)
|
|
}
|
|
|
|
if let notification = try? jsonDecoder.decode(NotificationModel.self, from: data) {
|
|
os_log("Notification erhalten", log: LOG, type: .info)
|
|
NotificationCenter.default.post(name: Notification.Name(rawValue: notification.name), object: nil)
|
|
}
|
|
|
|
if let eloData = try? jsonDecoder.decode(EloDataForPeer.self, from: data) {
|
|
print("Recieved elo data: \(eloData.scoreToReport)")
|
|
let score = GKScore(leaderboardIdentifier: EloHelper.IDENTIFIER, player: self.localPlayer)
|
|
score.value = eloData.scoreToReport
|
|
GKScore.report([score], withCompletionHandler: { error in
|
|
os_log("New Scores reported to EloSystem", log: self.LOG, type: .info)
|
|
})
|
|
}
|
|
MultiplayerNetwork.sharedInstance.isSending = false
|
|
}
|
|
|
|
func initAndSendMap() -> Void {
|
|
self.gameScene = GameScene(size: self.menusc!.size)
|
|
let mapModel = MapFactory(scene: self.gameScene!, entityManager: entityManager).load()
|
|
os_log("Map wurde erstellt", log: LOG, type: .info)
|
|
MultiplayerNetwork.sharedInstance.sendMapModelToPlayers(mapModel: mapModel)
|
|
os_log("Map wurde an Peer gesendet", log: LOG, type: .info)
|
|
DataService.sharedInstance.setSnapshotModel(snapshotModel: entityManager.getSnapshotModel())
|
|
os_log("SnapshotModel wurde erstellt", log: LOG, type: .info)
|
|
}
|
|
|
|
func getGKPlayerByUsername(displayName: String) -> GKPlayer? {
|
|
let nilGK : GKPlayer? = nil
|
|
|
|
if GKLocalPlayer.local.displayName == displayName {
|
|
return GKLocalPlayer.local
|
|
}
|
|
|
|
for player in myMatch!.players {
|
|
if player.displayName == displayName {
|
|
return player
|
|
}
|
|
}
|
|
return nilGK
|
|
}
|
|
func sendStateToPeers(state: State){
|
|
let encoder = JSONEncoder()
|
|
let encoded = (try? encoder.encode(state))!
|
|
MultiplayerNetwork.sharedInstance.sendData(data: encoded)
|
|
}
|
|
|
|
func sendRandomNumberToAllPeers(in match: GKMatch){
|
|
let encoder = JSONEncoder()
|
|
let encoded = (try? encoder.encode(localPlayerRandomNumber))!
|
|
MultiplayerNetwork.sharedInstance.sendData(data: encoded)
|
|
}
|
|
|
|
func player(_ player: GKPlayer, didAccept invite: GKInvite) {
|
|
os_log("Einladung angenommen", log: LOG, type: .info)
|
|
let matchmakerVC = GKMatchmakerViewController.init(invite: invite)
|
|
matchmakerVC!.matchmakerDelegate = self
|
|
viewController?.present(matchmakerVC!, animated: true, completion: nil)
|
|
}
|
|
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
|
|
viewController.dismiss(animated: true, completion: nil)
|
|
}
|
|
|
|
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
|
|
viewController.dismiss(animated: true, completion: nil)
|
|
}
|
|
|
|
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
|
|
viewController.dismiss(animated: true, completion: nil)
|
|
myMatch = match
|
|
if !isMatchStarted && match.expectedPlayerCount == 0 {
|
|
myMatch?.delegate = self
|
|
sendRandomNumberToAllPeers(in: self.myMatch!)
|
|
os_log("Random Number wurde an den anderen Spieler gesendet", log: LOG, type: .info)
|
|
}
|
|
}
|
|
|
|
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
|
|
gameCenterViewController.dismiss(animated: true, completion: nil)
|
|
}
|
|
|
|
func disconnect() {
|
|
if myMatch != nil {
|
|
myMatch?.disconnect()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Notification.Name {
|
|
static let presentGame = Notification.Name(rawValue: "presentGame")
|
|
static let authenticationChanged = Notification.Name(rawValue: "authenticationChanged")
|
|
}
|