当 matchData 更改时,不能可靠地调用 GameKit Turn-based 侦听器

GameKit Turn-based listener is not reliably called when matchData changes

我正在为我的纸牌游戏使用 Game Center 回合制比赛。感觉很合适,因为人们有时想在转弯之间查看电子邮件或写短信。一些用户表示,他们非常希望能够拥有非常异步的播放体验。

对于那些在他们的回合之间保持游戏开放的人,我想更新屏幕以反映其他玩家在他们的回合中所做的事情。我已经在 GKLocalPlayer 上设置了一个响应 player:receivedTurnEventForMatch:didBecomeActive 的监听​​器。文档说,当比赛数据被另一个玩家保存时,即使没有轮到该玩家(当前设备上的玩家),也会调用它。这似乎并非 100% 正确。事实上,似乎只有三分之一的比赛数据被其他玩家保存。轮到玩家时似乎更可靠,但即使那样也不是 100% 可靠。

我在 GKTurnBasedMatch 上使用 saveCurrentTurnWithMatchData:completionHandler: 来保存不结束当前玩家回合的比赛数据,我在 GKTurnBasedMatch 上调用 endTurnWithNextParticipants:turnTimeout:matchData:completionHandler: 来保存当前玩家的回合结束时的数据。在某些情况下,我想使用更新的 matchData 调用 saveCurrentTurn…。在我的游戏中,您也可以在多人游戏中玩电脑。因此,人类玩家可能会出牌,然后计算机可能会在 GKPlayer 的回合结束之前出牌。也有个别玩家可能会玩两次的情况。 (例如,一位玩家在一墩牌中打出最后一张牌。该玩家拿下这墩牌并开始下一墩。)

我已经围绕这个设置了大量的日志记录,我可以清楚地看到一个设备调用 saveCurrentTurn… 并且调用 completionHandler 没有错误,而另一个设备没有收到调用通知对于 player:receivedTurnEvent… 我还添加了日志记录以验证每次我调用 saveCurrentTurn… 时我都是用新的 matchData 调用它。我没有打多余的电话。

如果我转到未获取更新的 matchData 的设备并强制它再次加载匹配的 matchData,它会获取更新的数据。所以,它肯定得救了。

我已经尝试限制对 saveCurrentTurn… 的调用,这样它们就不会立即连续发生,但这并没有帮助。

我测试的两个设备都是 运行 iOS 8.4。 iOS 8.3 中似乎有一个问题现在已修复(). This Apple forum post 2 年前也报告了这个问题,并且似乎已提交错误报告并标记为已修复。

还有其他人看过吗?我很想知道我做错了什么。非常欢迎任何想法。

我也在做类似的事情。在我的游戏中,每个玩家都有多个棋子,当每个棋子移动时保存比赛,以便其他玩家 - 如果他们在游戏中 - 可以实时观看正在发生的事情。就像您描述的那样,Game Center 消息传递几乎完全没用。

如您所述,在 8.3 中,"end of turn" 消息已完全损坏。从 8.4 开始,它们 大多数 ,但不是全部。如您所见,"match has been saved" 通知也不稳定。以下是我用来提高成功率的一些技巧:

  1. 放慢保存速度。如果您保存得太快,只有最后一个会到达收件人手中。我设置了一个 NSArray 队列,每次我想保存匹配项时,我都会将新的 matchData 添加到该队列中。我有一个计时器循环 运行 执行实际的 saveCurrentTurnWithMatchData,如果保存成功则将项目从堆栈中弹出,然后设置一个新的计时器稍后再次调用自身。我正在使用 2 秒间隔,这似乎运行良好。

  2. 追加每条新数据,不要覆盖。在每条数据上放置一个序列号。因此,如果您保存序列号 1、2、3 和 4,但收件人仅收到 #4 的通知,则匹配对象中存在 1、2 和 3 的记录。收件人需要跟踪它读取的最后一条记录,然后在收到更新的 matchData 时从该点开始遍历任何新记录。

  3. 我还使用队列的 NSArray writeToFile: 函数来维护待处理保存的列表。如果用户在刷新队列之前退出游戏,我会在下次启动时从磁盘重新加载队列 NSArray

  4. 请注意,即使使用此机制,对收件人的通知也不稳定。一般来说,都是4+批次到货。然后什么都没有发生,直到再发生 3 或 4 次保存,它们再次全部显示在一起。进行 1 次保存并让游戏等待 10 分钟可能永远不会在接收者的机器上生成通知。但是,如果你连续保存 4 或 6 次,它们往往会突然出现。

  5. 有时,通知只会停止几个小时。不确定这是沙盒缺陷还是一般游戏中心缺陷。没有任何类型的故障,消息只是暂时停止工作。有时,第二天早上,他们突然出现。有时不是。最后,我不再依赖通知。我设置了另一个定时器循环来持续下载比赛。它检查是否轮到我了,它检查是否有新的更新被添加到匹配数据中。然后调用 player:receivedTurnEventForMatch:didBecomeActive。据 receivedTurnEventForMatch: 所知,它是因为一个事件而启动的,并且它愉快地继续它的业务。

  6. 保存匹配似乎非常及时。如果您没有收到错误,似乎可以肯定更新后的比赛立即可供其他玩家使用……他们只需要知道如何使用它。但是,必须将消息传递框架视为完全不可靠且无保证的。因此,定时器循环不断轮询匹配项。

编辑:可以说,一旦我实施了#2,#1 就不重要了。收件人收到的任何通知都会触发读取数据中的所有新记录。但是,这个 "hardening" 在过去的几个月里随着我与 Game Center 的缺点作斗争而发生了变化。我只是还没来得及删除 #1。