我正在尝试使用 Game Center 创建实时多人游戏。对于匹配,我使用以下代码使用编程方法:
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error)
{
// Process the error.
NSLog(@" error => %@ ", [error userInfo] );
}
else if (match != nil)
{
NSLog(@"Match Found _-----------");
currentMatch = match;
match.delegate = self;
NSLog(@"Expected player count:%ld",match.expectedPlayerCount);
if ( match.expectedPlayerCount == 0)
{
NSLog(@"Ready to start match!");
}
}
}];
目前,当找到匹配项时,代码会生成以下错误:
ABC-mobile[342:26698] [log] [ERROR] ReXmitCollectionRequest:640 /BuildRoot/Library/Caches/com.apple.xbs/Sources/AVConference/AVConference-1020.31/ICE.subproj/Sources/ICEMessage.c:640: ReXmit [SNATMAP_REQUEST] (1:0) from [192.168.0.104:16402] to [17.133.234.32:16384] failed (801A0002)
ABC-mobile[342:26698] [log] [ERROR] -[GKConnectionInternal internal_setRemoteConnectionData:fromParticipantID:pendingConnectionPIDList:]:1041 GCKSessionPrepareConnection FAILED(80150016)
我正在使用 Cocos2D-X 游戏引擎,并且我从 C++ 函数调用此方法。
我将不胜感激有关此主题的任何建议和想法。谢谢你。
解决方案:
使用纯 Objective-C 代码(文件扩展名应为 .m 而不是 .mm)。在 Objective-C++(扩展名为 .mm 的文件)中编写一个包装类来调用这些 Game Center 方法。
我最近遇到了这个问题,网上关于它的信息很少。
2023-10-31 17:44:22.256821+0900 Real-Time Game Sample[663:76416] [ViceroyTrace] [ERROR] ReXmitCollectionRequest:629 /Library/Caches/com.apple.xbs/Sources/AVConference/ICE.subproj/Sources/ICEMessage.c:629: ReXmit [SNATMAP_REQUEST] (1:0) from [183.102.108.243:16402] to [17.188.182.97:3480] failed (801A0002)
2023-10-31 17:44:22.258946+0900 Real-Time Game Sample[663:76416] [ViceroyTrace] [ERROR] ReXmitCollectionRequest:629 /Library/Caches/com.apple.xbs/Sources/AVConference/ICE.subproj/Sources/ICEMessage.c:629: ReXmit [SNATMAP_REQUEST] (1:0) from [183.102.108.243:16402] to [17.188.182.97:3480] failed (801A0002)
... HUNDREDS MORE...
2023-10-31 17:44:26.736101+0900 Real-Time Game Sample[663:76416] [ViceroyTrace] [ERROR] ReXmitCollectionRequest:629 /Library/Caches/com.apple.xbs/Sources/AVConference/ICE.subproj/Sources/ICEMessage.c:629: ReXmit [SNATMAP_REQUEST] (1:0) from [183.102.108.243:16402] to [17.188.182.97:3480] failed (801A0002)
2023-10-31 17:44:26.737198+0900 Real-Time Game Sample[663:76416] [ViceroyTrace] [ERROR] ReXmitCollectionRequest:629 /Library/Caches/com.apple.xbs/Sources/AVConference/ICE.subproj/Sources/ICEMessage.c:629: ReXmit [SNATMAP_REQUEST] (1:0) from [183.102.108.243:16402] to [17.188.182.97:3480] failed (801A0002)
2023-10-31 17:44:26.738326+0900 Real-Time Game Sample[663:76416] [ViceroyTrace] [ERROR] -[GKConnectionInternal internal_setRemoteConnectionData:fromParticipantID:pendingConnectionPIDList:]:1047 GCKSessionPrepareConnection FAILED(80150016)
Viceroy 显然是
GameKit
用于实时连接的点对点连接框架。这是一个内部错误,不提供任何失败原因的信息。
当满足
GKMatch
请求后生成的 findMatch
对象没有 delegate
时,就会发生这种情况。它尝试将信息推送给委托,但失败,导致会话无法连接。
例如,如果您有
public func findPlayer() async {
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
let match: GKMatch
do {
match = try await GKMatchmaker.shared().findMatch(for: request)
} catch {
print("Error: \(error.localizedDescription).")
return
}
start(match: match)
GKMatchmaker.shared().finishMatchmaking(for: match)
}
然后
start(match:)
函数看起来像这样
public func start(match: GKMatch) {
guard match.expectedPlayerCount == 0
else {
return
}
currentMatch = match
currentMatch?.delegate = self
}
请注意,委托不是根据
expectedPlayerCount
是否为 0 设置的。这导致了失败,在找到匹配项后立即设置委托可以解决问题。
所以最终的工作解决方案如下:
public func findPlayer() async {
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
let match: GKMatch
do {
match = try await GKMatchmaker.shared().findMatch(for: request)
} catch {
print("Error: \(error.localizedDescription).")
return
}
currentMatch = match
currentMatch?.delegate = self
start(match: match)
GKMatchmaker.shared().finishMatchmaking(for: match)
}
public func start(match: GKMatch) {
guard match.expectedPlayerCount == 0
else {
return
}
// Start Game Logic
}
// MARK: - GKMatch Delegate
public func match(
_ match: GKMatch,
player: GKPlayer,
didChange state: GKPlayerConnectionState
) {
switch state {
case .connected:
print("\(player.displayName) Connected")
case .disconnected:
print("\(player.displayName) Disconnected")
default:
print("\(player.displayName) Connection Unknown")
}
start(match: match)
}
我绝不会建议在您自己的云基础设施上部署代码进行匹配。我使用 AWS lambda + dynamodb 组合做到了这一点。 Dynamo db 促进了表键上的原子操作。这些关键点可能是你匹配玩家的技能点。 Firebase云功能+RealtimeDB(也可以尝试CloudStore。这是Firebase的新产品)是开发匹配框架的另一种选择。它不提供密钥的原子性,但还有另一个 PushKey 的概念。这也有效。
这两家都是主要的云供应商,因此您不必担心延迟或停机。我在美国的 Firebase RealtimeDB 上建立了我的中心,在印度,我能够在 500 毫秒内将事件传输给印度的另一位玩家。
这两者都有一定的免费连接/请求限制(我猜 Firebase 的免费连接数量比 AWS 更多。您可能需要检查一下)。因此,在您的游戏真正开始赚钱之前,您很长一段时间都不会产生任何费用。在我的 AWS Lambda + DynamoDB 组合上,我每天可以进行 11k 次匹配,而无需支付一分钱。
最重要的是,这两个国家都提供区域中心。因此,当您扩大规模时,您可以创建多区域中心。
但是这两个供应商可能都不支持 C++ 或 Objective-C++。我在 Javascript 和 JAVA 上开发了我的模型。也许也支持其他一些语言。您可能想检查一下。