In my SceneKit game I'm able to connect two players with GKMatchmakerViewController. Now I want to support the scenario where one of them disconnects and wants to reconnect. I tried to do this with this code:
nonisolated public func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState) {
Task { @MainActor in
switch state {
case .connected:
break
case .disconnected, .unknown:
let matchRequest = GKMatchRequest()
matchRequest.recipients = [player]
do {
try await GKMatchmaker.shared().addPlayers(to: match, matchRequest: matchRequest)
} catch {
}
@unknown default:
break
}
}
}
nonisolated public func player(_ player: GKPlayer, didAccept invite: GKInvite) {
guard let viewController = GKMatchmakerViewController(invite: invite) else {
return
}
viewController.matchmakerDelegate = self
present(viewController)
}
But after presenting the view controller with GKMatchmakerViewController(invite:), nothing else happens. I would expect matchmakerViewController(_:didFind:) to be called, or how would I get an instance of GKMatch?
Here is the code I use to reproduce the issue, and below the reproduction steps.
Code
Run the attached project on an iPad and a Mac simultaneously.
On both devices, tap the ship to connect to GameCenter.
Create an automatched match by tapping the rightmost icon on both devices.
When the two devices are matched, on iPad close the dialog and tap on the ship to disconnect from GameCenter.
Wait some time until the Mac detects the disconnect and automatically sends an invitation to join again.
When the notification arrives on the iPad, tap it, then tap the ship to connect to GameCenter again. The iPad receives the call player(_:didAccept:), but nothing else, so there’s no way to get a GKMatch instance again.
GameKit
RSS for tagCreate apps that allow players to interact with each other using GameKit.
Post
Replies
Boosts
Views
Activity
Hi,
I have a test app with a single "game centre achievement" and I am running it on my iPad and unable to list that achievement with
GameCenterManager.shared.loadAchievements
The app is still in version 1.0, prepare for submission status, (it is not ready for review submission). Game Center entitlement is added for the app and the achievement is added to the Game Center section of app. However it is marked as NotLive.
I am using a sandbox account to login to game centre on the iPad and I can't fetch this achievement. Is it because it is "NotLive". ? How do I test my Game Center achivement on the device without releasing it yet.
GKGameCenterViewController won't turn off.
With Core and GameKit from GitHub apple/unityplugins,
I succeeded in logging in and displaying GKGameCenterViewController.
Other leaderboards and everything work fine, but when I press X on GameCenter to return to the game, nothing happens.
I tried debugging by printing logs here and there in the plugin to check, but I didn't get any results.
When I press X, I couldn't get any logs or responses. It was like a button with no listener attached. No, it was more like an image.
Based on the community posts that said it worked fine before, it seems that the recent GameCenter update was not applied to the plugin, was omitted, or changed, causing a mismatch.
Hi,
I tried to save the game progress using the official Apple plugin for Unity but the crash happened when I active the "iCloud Documents" inside capabilities and when deactivated it this error message appeared:
Code=27 Domain=GKErrorDomain Description=The requested operation could not be completed because you are not signed in to iCloud or have not enabled iCloud Drive. (UbiquityContainerUnavailable)
Authentication with Game Center works fine using the Core plugin, but nothing works correctly when I use the GameKit plugin.
Note:
I already active iCloud for app Identifier.
Tichnecal informations:
Unity version: 2022.3.47f1 LTS
XCode 16
Swift 6
GameKit-3.0.0 (Apply unity plugin)
Core-3.1.5 (Apply unity plugin)
I'm displaying a GKGameCenterViewController after successfully authenticating and on iOS 18.0 and 18.1, I get a black screen. As a sanity check GKLocalPlayer.local.isAuthenticated is also returning true. The same code works just fine on iOS 17. Is there something that needs to be done on iOS 18 and above?
I'm sure this question was asked many times before but I cannot find a good answer. In my case it just doesn't work.
Here's what I did
Created a couple of test user accounts on appstore connect under the sandbox section.
Launched two different simulators via xcode. On each simulator I logged in into test icloud account and game center accordingly.
Deployed and launched my code via xcode.
What happens is that GameKit code fails to find any peers no matter what I do. Sending Invite doesn't work either because the simulator displays an error message saying "you need to log-in into icloud account first" although it's already logged in. I tried the same code on two different physical devices with two real icloud accounts and it works as expected but it's not a viable path to develop and debug an app. I'm using the latest Xcode 16.1 running on 15.1.
Anybody has any clue how to solve this ?
Hi there,
With a couple of other developers we have been busy with migrating our SpriteKit games and frameworks to Swift 6.
There is one issue we are unable to resolve, and this involves the interaction between SpriteKit and GameplayKit.
There is a very small demo repo created that clearly demonstrates the issue. It can be found here:
https://github.com/AchrafKassioui/GameplayKitExplorer/blob/main/GameplayKitExplorer/Basic.swift
The relevant code also pasted here:
import SwiftUI
import SpriteKit
struct BasicView: View {
var body: some View {
SpriteView(scene: BasicScene())
.ignoresSafeArea()
}
}
#Preview {
BasicView()
}
class BasicScene: SKScene {
override func didMove(to view: SKView) {
size = view.bounds.size
anchorPoint = CGPoint(x: 0.5, y: 0.5)
backgroundColor = .gray
view.isMultipleTouchEnabled = true
let entity = BasicEntity(color: .systemYellow, size: CGSize(width: 100, height: 100))
if let renderComponent = entity.component(ofType: BasicRenderComponent.self) {
addChild(renderComponent.sprite)
}
}
}
@MainActor
class BasicEntity: GKEntity {
init(color: SKColor, size: CGSize) {
super.init()
let renderComponent = BasicRenderComponent(color: color, size: size)
addComponent(renderComponent)
let animationComponent = BasicAnimationComponent()
addComponent(animationComponent)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@MainActor
class BasicRenderComponent: GKComponent {
let sprite: SKSpriteNode
init(color: SKColor, size: CGSize) {
self.sprite = SKSpriteNode(texture: nil, color: color, size: size)
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BasicAnimationComponent: GKComponent {
let action1 = SKAction.scale(to: 1.3, duration: 0.07)
let action2 = SKAction.scale(to: 1, duration: 0.15)
override init() {
super.init()
}
override func didAddToEntity() {
if let renderComponent = entity?.component(ofType: BasicRenderComponent.self) {
renderComponent.sprite.run(SKAction.repeatForever(SKAction.sequence([action1, action2])))
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
As SKNode is designed to run on the MainActor, the BasicRenderComponent is attributed with MainActor as well. This is needed as this GKComponent is dedicated to encapsulate the node that is rendered to the scene.
There is also a BasicAnimationComponent, this GKComponent is responsible for animating the rendered node.
Obviously, this is just an example, but when using GameplayKit in combination with SpriteKit it is very common that a GKComponent instance manipulates an SKNode referenced from another GKComponent instance, often done via open func update(deltaTime seconds: TimeInterval) or as in this example, inside didAddToEntity.
Now, the problem is that in the above example (but the same goes foupdate(deltaTime seconds: TimeInterval) the methoddidAddToEntity is not isolated to the MainActor, as GKComponent is not either.
This leads to the error Call to main actor-isolated instance method 'run' in a synchronous nonisolated context, as indeed the compiler can not infer that didAddToEntity is isolated to the MainActor.
Marking BasicAnimationComponent as @MainActor does not help, as this isolation is not propogated back to the superclass inherited methods.
In fact, we tried a plethora of other options, but none resolved this issue.
How should we proceed with this? As of now, this is really holding us back migrating to Swift 6. Hope someone is able to help out here!
The welcome banner is off the top left side of the screen instead of coming down the center. This behavior is encountered when running my iOS application on macOS.
Updated to GPT 2 with the app format and whisky in October. I'm using steam in GPT to play the windows only games. The games consistently crash my computer to restart when I played games like Liar's Bar and Phasmophobia, the latter even with its performance optimization update released today. Both of them do that when I load into the game room, so the bar/ghost house or even while loading. It ran Outpath properly though, which was something with much lower quality than LB and Phas. I don't think it's a simple RAM config issue because Phasmophobia ran fine for me with older versions in GPT 1 although I did experience occasional crashes but I think those were only crashing the game not my mac. I'm not sure what I'm doing wrong that I can't run those games or if it's a GPT problem. I'm using a MPB Pro M1 with 16GB memory on Sequoia 15.0.1.
Leaderboard has not worked for past two days. What’s up with that?
I have created a turn based game using GameKit. Everything is pretty much done, last thing left to do is the turn time out.
I am passing GKTurnTimeoutDefault into the timeout argument in:
func endTurn(withNextParticipants nextParticipants: [GKTurnBasedParticipant], turnTimeout timeout: TimeInterval, match matchData: Data)
However when I check the .timeoutDate property of the GKTurnBasedParticipant participants, the value is always nil.
What am I doing wrong? Am I checking the right property or is there another one instead that I don't know about? I have tried passing different values to the timeout parameter but the timeoutDate is always nil.
Has anyone successfully implemented a timeout using GKTurnBasedMatch ?
Hi All!
I'm being asked to migrate an app which utilizes iCloud KVS (Key Value Storage). This ability is a new-ish feature, and the documentation about this is sparse [1]. Honestly, the entire documentation about the new iCloud transfer functionality seems to be missing. Same with Game Center / GameKit. While the docs say that it should work, I'd like to understand the process in more detail.
Has anyone migrated an iCloud KVS app? What happens after the transfer goes through, but before the first release? Do I need to do anything special? I see that the Entitlements file has the TeamID in the Key Value store - is that fine?
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
Can someone please share their experience?
Thank you!
[1] https://developer.apple.com/help/app-store-connect/transfer-an-app/overview-of-app-transfer
I just built Core and GameKit without errors. The command line I used was the following: python3 build.py -p Core GameKit -m macOS -c "Apple Development ID (redacted)" When importing these packages into Unity, as soon as the editor refreshes I get these errors:
DllNotFoundException: GameKitWrapper assembly:<unknown assembly> type:<unknown type> member:(null)
And
DllNotFoundException: AppleCoreNativeMac assembly:<unknown assembly> type:<unknown type> member:(null)
And
Apple Unity Plug-ins] No Apple native plug-in libraries found. Were the libraries built with the build script (build.py), xcodebuild, or Xcode? Was any output generated from the build script/tool? Were there any errors or issues? Please check to ensure that libraries (.a, .framework, or .bundle files) were created and saved to each plug-in's "NativeLibraries~" folder.
I made sure that the libraries were saved to this NativeLibraries folder. I made sure to update xcode, python, npm and Unity to the latest version, got the most recent commity from Github (Sept. 17th) but the errors persist. The errors also occur right as the game starts in a built player. Also occurs in a blank Unity project, where I tested both 2022.3.17f and 2022.3.48f.
The versions I was trying to import was Core 3.1.4 and GameKit 3.0.0. Same issue with Core 3.1.3 and Gamekit 2.2.2. Last version I tried that works was Core 1.05 and GameKit 1.04.
I haven't seen anyone else encounter this on these forums so I'm guessing that I'm personally doing something wrong rather than there being an issue with the plugins themselves, but what am I doing wrong?
Hello,
I’m working with the GameKit API, and I am encountering an issue when submitting a player’s score to a leaderboard at the end of a game.
Goal:
After submitting the new score to a leaderboard, I want to immediately fetch and display the updated leaderboard that reflects the new score.
Problem:
After successfully submitting the player’s score, when I fetch the leaderboard, the entries are not updated right away. The fetched leaderboard still shows the outdated player score.
Is this delay in updating the leaderboard expected behavior, or am I missing something in my implementation?
Steps to Reproduce:
Submit the local player’s score to Leaderboard X.
On successful submission, fetch the leaderboard entries for Leaderboard X.
Expected Result:
The fetched leaderboard should reflect the updated player score immediately.
Actual Result:
The fetched leaderboard shows the outdated score, with no immediate update.
As a workaround, I update the leaderboard myself locally, that does the job, but is error-prone and require more efforts.
Hi,
I created a leaderboard in my application, and a method to record a new score:
GKLeaderboard.loadLeaderboards(IDs: [leaderboardID]) { (leaderboards, error) in
if let error = error {
print("Error loading leaderboards: \(error.localizedDescription)")
}
guard let leaderboard = leaderboards?.first else {
print("Leaderboard not found")
return
}
leaderboard.submitScore(score, context: 0, player: self.localPlayer) { error in
if let error = error {
print("Error reporting score: \(error.localizedDescription)")
} else {
print("Score reported successfully!")
}
}
}
}
When debuging, this method is correctly called and I have a success, so I tried to test it with an internal TestFlight release.
The leaderboard is never updated.
Is there a way to perform a test of a leaderboard before publishing the app?
I have the same question for achievements:
let achievement = GKAchievement(identifier: identifier)
achievement.percentComplete = percentComplete
GKAchievement.report([achievement]) { error in
if let error = error {
print("Error reporting achievement: \(error.localizedDescription)")
}
}
}
Thanks!
Hello!
Bare with me here, as there is a lot to explain!
I am working on implementing a Game Center high score leaderboard into my game. I have looked around for examples of how to properly implement this code, but have come up short on finding much material. Therefore, I have tried implementing it myself based off information I found on apples documentation.
Long story short, I am getting success printed when I update my score, but no scores are actually being posted (or at-least no scores are showing up on the Game Center leaderboard when opened).
Before I show the code, one thing I have questioned is the fact that this game is still in development. In AppStoreConnect, the status of the leaderboard is "Not Live". Does this affect scores being posted?
Onto the code. I have created a GameCenter class which handles getting the leaderboards and posting scores to a specific leaderboard. I will post the code in whole, and will discuss below what is happening.
PLEASE VIEW ATTACHED TEXT TO SEE THE GAMECENTER CLASS!
GameCenter class - https://developer.apple.com/forums/content/attachment/0dd6dca8-8131-44c8-b928-77b3578bd970
In a different GameScene, once the game is over, I request to post a new high score to Game Center with this line of code:
GameCenter.shared.submitScore(id: GameCenterLeaderboards.HighScore.rawValue)
Now onto the logic of my code. For the longest time I struggled to figure out how to submit a score. I figured out that in Xcode 12, they deprecated a lot of functions that previously worked for me. Not is seems that we have to load all leaderboards (or the ones we want). That is the purpose behind the leaderboards private variable in the Game Center class.
On the start up of the app, I call authenticate player. Once this callback is reached, I call loadLeaderboards which will load the leaderboards for each string id in an enum that I have elsewhere. Each of these leaderboards will be created as a Leaderboard object, and saved in the private leaderboard array. This is so I have access to these leaderboards later when I want to submit a score.
Once the game is over, I am calling submitScore with the leaderboard id I want to post to. Right now, I only have a high score, but in the future I may add a parameter to this with the value so it works for other leaderboards as well. Therefore, no value is passed in since I am pulling from local storage which holds the high score.
submitScore will get the leaderboard from the private leaderboard array that has the same id as the one passed in. Once I get the correct leaderboard, I submit a score to that leaderboard. Once the callback is hit, I receive the output "Successfully submitted score to leaderboard". This looks promising, except for the fact that no score is actually posted.
At startup, I am calling updatePlayerHighScore, which is not complete - but for the purpose of my point, retrieves the high score of the player from the leaderboard and is printing it out to the console. It is printing out (0), meaning that no score was posted.
The last thing I have questions about is the context when submitting a score. According to the documentation, this seems to just be metadata that GameCenter does not care about, but rather something the developer can use. Therefore, I think I can cross this off as causing the problem.
I believe I implemented this correctly, but for some reason, nothing is posting to the leaderboard. This was ALOT, but I wanted to make sure I got all my thoughts down.
Any help on why this is NOT posting would be awesome! Thanks so much!
Mark
Hello,
Asking the following as, I was unable to find answers via search on the forum and in the documentation:
Invitations sent via iMessage seem to work correctly with my custom image ( GKMessageImage.png ) however, notifications sent to Game Center Friends via invites generated in Game Center do not include the custom image ( GKMessageImage.png ).
Questions:
Is this expected behavior? Is there a different way to customize the image in the notification? Note the Game Center notification includes the App name correctly.
I also noted in the WWDC session in 2016 ( saw video recently ) that there was some mention of no longer adding friends via Game Center. Is that currently true?
Thanks in advance.
Hello,
I would like to know if anyone has or still using the GKVoiceChat capabilities in their apps. I wanted to use it for my online game but I am coming across issues using it and wondering if their are alternatives?. The documentation mentions to use Share-play but that wont be possible with random online players. Any help will be appreciated!.
Hello, I try to invite a friend to play my app , however when the friend try to press invite link component via iMessage, it shows “Retrieving” and then disappear, nothing happens,
it doesn't redirect to my app, what I'm missing? or doing wrong I can leave some part of my code
import Foundation
import GameKit
extension RealTimeGame: GKLocalPlayerListener {
/// Handles when the local player sends requests to start a match with other players.
func player(_ player: GKPlayer, didRequestMatchWithRecipients recipientPlayers: [GKPlayer]) {
print("\n\nSending invites to other players.")
}
/// Presents the matchmaker interface when the local player accepts an invitation from another player.
func player(_ player: GKPlayer, didAccept invite: GKInvite) {
// Present the matchmaker view controller in the invitation state.
if let viewController = GKMatchmakerViewController(invite: invite) {
viewController.matchmakerDelegate = self
rootViewController?.present(viewController, animated: true) { }
}
}
}
also I don't have "<key>CFBundleURLTypes</key>" in my info.plist, I don't know I need that or not...
Why is the GameController framework loaded
I am checking the launch time of our app, using Instruments->App launch
I was confused to find the GameConroller framework loaded
I check the project, in the plist file, no configuration GCSupportedGameControllers, GCSupportsControllerUserInteraction related key.
What else causes the GameController framework to load?