Player swipe to remove match - ios

Let's say I have a turn based match with two players. At some point player 1 recognizes that he is about to lose the game. When it is Player 1's turn, he uses Game Center App to do a swipe to remove the match.
Issues:
A. Take turn timer never expires on Player 1. So the match's turn will not switch to Player 2 when the time expired.
B. The game also offers a view only mode so players can view the game progress while he is out of turn. But since no status was updated to indicate that Player 1 had removed the match manually. App can offers no resolution. Also, you can only end match while it is your turn.
Ideally, I want to declare Player 2 as a winner and end the match.
How do you handle in this situation?

I finally found a workaround for this.
If you delete a match, then call GKTurnBasedMatch:loadMatchesWithCompletionHandler, the deleted match doesn't appear (as expected). However, it turns out that you can still re-download the deleted match using GKTurnBasedMatch:LoadMatchWithID, if you happen to still have the deleted match's ID.
I think we can reasonably assume that The Cheater is going to play the game again; otherwise, why would they care about incurring a loss? Therefore, I implemented the following:
Maintain a table locally, on the device, of matches.
On startup, pull the list of local player's matches from Game Center and compare against my local list.
When The Cheater recognizes the situation and deletes the match using the Game Center interface, the match is removed from Game Center, but not from my local DB. When The Cheater starts my game again, I see that they have more matches locally than on Game Center.
I then call either participantQuitInTurnWithOutcome or participantQuitOutOfTurnWithOutcome, as appropriate, with an outcome of GKTurnBasedMatchOutcomeLost.
This passes the turn to the next player and records a loss for The Cheater. It won't work if the cheater never plays the game again, though. (But, if they're not playing, they're not wrecking any more matches, so the chaos is contained)

Related

How to implement an agar.io like game's networking model

I'm wondering what's the best way to to implement the networking model for a game like agar.io - I'm assuming it's an authoritative server, but I'm wondering about:
Does every player "owns" his position, and sends it to the server, or does every player merely sends his input and everything is fully authoritative on the server?
How does it decide what data to send to which player? I'm assuming that for every player I would have to iterate on all players in the server and check if they are currently (or soon to be) visible, and if so begin sending data on them
Where do the actual collisions happen, and how to handle lag?
I'm well aware of the ways to handle this in an FPS game (player prediction, rewind replay, lag compensation, etc) - but it's usually done on a much smaller scale, and I assume a simpler solution is good enough for a casual game like that with thousands of concurrent players.
the model in agario is shown by 2 things:
You can see other players eating the same dots, so that shows the players are receiving the positions of all players (probably around 5 times a second) and then the dots appearing and disappearing are handled client side. If the dots weren't handled client side that would cost huge bandwidth. That also means that you receive a message containing positions of all dots on startup, which makes sense because not all the dots are there in the beginning
The inputs from players to server are sent as opposed to positions, because otherwise it would be extremely hackable. The logic for collisions are then handled on the server
If the other player's inputs were broadcasted (instead of positions) from the server to the clients after the server got them small differences would build up like the butterfly effect and cause chaos
I'm pretty sure the inputs are only sent 5 times per second because there's a problem with websockets that causes packets sent more than 5 times per second to be clumped together

How to detect when Game Center turn based match has ended in iOS9?

I'm totally lost with how to implement a turn-based game. I've been trying to use the GKLocalPlayerListener methods to handle turn-based in iOS9. The only method that ever fires is receivedTurnEventForMatch, which leaves me with no method that I know of that calls an end game routine for each player. I am trying to handle turn-based matches inside of my app using the Game Center match maker view controller and delegate methods. I read that GKLocalPlayerListener methods work for matches when going through the actual Game Center app (Apple docs don't mention this). So if that's true, then GKLocalPlayerListener is not an option for my app?
What can I do to detect when a match ends? I want to keep a win-lose record for each player, so it's important that a routine is called for each player when a match ends.
The lifecycle of a turn based match looks like this:
Create a match
Invite others
Others join
Players take turns and pass the match object around (your game logic decides the order)
Players send exchanges back and forth (optional)
Players start leaving
----because they have been eliminated
----because they quit
----because they timed out
Someone Wins
If you are not the active player, you are notified when steps 3, 4, 7, 8 and 9 happen by playerReceivedTurnEventForMatch firing; however, as you can see from my answer here https://stackoverflow.com/a/34458493/1641444 playerReceivedTurnEventForMatch fires for a lot of different conditions, and it doesn't tell you which one triggered it. You have to discern that based on the status of the players, which player is the active player, and whatever other information you track in the match object.
You are notified of #5 by playerReceivedExchangeRequest firing (and Replies and Cancellation functions).
Your game logic will decide when to trigger #7. My preference is that the match object comes to the eliminated player, they are recognized as defeated, and calls participantQuitInTurnWithOutcome
Players decide when to trigger #8 by quitting, and the code calls either participantQuitInTurnWithOutcome or participantQuitOutOfTurnWithOutcome depending on their state.
Condition #9 is a real pain in the ass. Between limitations in the game design and outright bugs, timeouts can create several unrecoverable edge cases. Handling timeouts warrants its own full answer.
Finally, #10 is triggered by calling endMatchInTurnWithMatchData. GKTurnBasedEventHandlerDelegate and handleMatchEnded were deprecated in IOS7. When using GKLocalPlayerListner, you'll be notified of #10 by yet another occurrence of playerReceivedTurnEventForMatch
Edit--Clarifications based on followup questions:
Yeah, exactly. In your sendTurn function, when the game is over, don't call endTurnWithNextParticipant. Instead, set the each participant's status to indicate who won and who lost, and then call endMatchInTurnWithMatchData.
The other players will see playerReceivedTurnEventForMatch fire. You can discern from the match status and the player status that the game is over and decide what actions to take for that recipient.
To end a match, you should have your game call endMatchInTurnWithMatchData:completionHandler:
If you've implemented GKTurnBasedEventHandlerDelegate protocol on an object, your handleMatchEnded will get a push event.
More details in Apple's programming guide

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

I am using Game Center turn-based matches for my card game. It feels like a good fit because people want to check their email or write a text sometimes between turns. Some users have said that they do really want to be able to have a very asynchronous playing experience.
For the people that are keeping the game open between their turns, I want to update the screen to reflect things that the other players are doing on their turns. I have set up a listener on GKLocalPlayer that responds to player:receivedTurnEventForMatch:didBecomeActive. The documentation says that this will get called when match data is saved by another player even if it doesn't become the player's turn (the player on the current device). That doesn't appear to be true 100% of the time. In fact, it appears that it only gets called about 1 in 3 times that match data is saved by other players. It seems more reliable when it becomes the player's turn, but even that isn't 100% reliable.
I am using saveCurrentTurnWithMatchData:completionHandler: on GKTurnBasedMatch to save match data that doesn't end the current player's turn and I'm calling endTurnWithNextParticipants:turnTimeout:matchData:completionHandler: on GKTurnBasedMatch to save the data when it does end the current player's turn. There are a few scenarios where I want to call saveCurrentTurn… with updated matchData. In my game, you can have computers playing in your multiplayer game as well. So, a human player may play a card and then a computer may play a card before that GKPlayer's turn ends. There are also scenarios where an individual player may play twice. (eg. A player plays the last card on a trick. That player takes the trick and gets to lead the next trick.)
I have set up a ton of logging around this and I can see clear scenarios where one device calls saveCurrentTurn… and the completionHandler is called without an error and the other device doesn't get notified with a call to player:receivedTurnEvent… I have also added logging to verify that each time I'm calling saveCurrentTurn… that I'm calling it with new matchData. I'm not making redundant calls.
If I go to the device that didn't get the updated matchData and force it to load the matchData for the match again, it gets the updated data. So, it's definitely getting saved.
I have tried throttling the calls to saveCurrentTurn… so that they don't happen in immediate succession and that didn't help.
Both devices in my testing are running iOS 8.4. There appears to have been an issue in iOS 8.3 that is fixed now (see this question). This Apple forum post also reports this issue 2 years ago and it appears that bug reports were filed and marked fixed.
Has anyone else seen this? I would love to know that I'm doing something wrong. Any ideas are very welcome.
I do something similar. In my game, each player has multiple pieces, saving the match when each piece moves so that other players--if they're in the game--can watch what's happening in real time. Like you describe, the Game Center messaging is almost completely useless.
As you referenced, in 8.3, the "end of turn" messages were completely broken. As of 8.4, they happen most, but not all, of the time. As you're seeing, the "match has been saved" notifications are also erratic. Here are some tips I've used to increase the success rate:
Slow down the saves. If you save too fast, only the last one arrives at the recipient. I set up an NSArray queue, and each time I want to save the match, I add the new matchData to that queue. I have a timer loop running that does the actual saveCurrentTurnWithMatchData, pops the item off the stack if the save was successful, and then sets up a new timer to call itself again a little later. I'm using 2 second intervals which seems to be working well.
Append each new piece of data, don't overwrite. Put a sequence number on each piece of data. So, if you save seq numbers 1, 2, 3 and 4, but the recipient only receives a notice for #4, the records for 1, 2 and 3 are there in the match object. The recipient needs to track the last record it read, and then iterate through any new records from that point when it receives an updated matchData.
I also use the queue's NSArray writeToFile: function to maintain a list of the pending saves. If the user exits the game before the queue is flushed, I reload the queue NSArray from disk at the next startup
Note that even with this mechanism, the notifications to the recipient are erratic. Generally speaking, they arrive in batches of 4+. Then nothing happens until 3 or 4 more saves happen, which again all show up together. Making 1 save and letting the game sit for 10 minutes will probably never generate a notice on the recipient's machine. But, if you save 4 or 6 times in a row, all of them tend to show up in a burst.
Sometimes, the notifications just stop for a few hours. Not sure if this a sandbox flaw or a game-center-in-general flaw. There are no failures of any kind, the messages just stop working for a while. Sometimes, the next morning, they show up in a burst. Sometimes not. In the end, I've stopped relying on the notifications. I set up another timer loop to continuously download the match. It checks if it has become my turn or not, it checks if new updates have been added to the matchData. Then calls player:receivedTurnEventForMatch:didBecomeActive. As far a receivedTurnEventForMatch: knows, it was launched because of an event and it merrily goes on about its business.
It does seem that saving the match is pretty prompt. If you don't get an error, it seems pretty certain that the updated match is immediately available for other players to consume... they just need to know to consume it. The messaging framework, though, has to be viewed as completely unreliable and non-guaranteed. Hence, the timer loop to continuously poll the match.
Edit: arguably, once I implemented #2, #1 shouldn't really matter. Any notification received by the recipient will trigger reading all new records in the data. But, this "hardening" has evolved over the past few months as I wrestle with Game Center's shortcomings. I just haven't gotten around to removing #1.

Does GameKit hosted matchmaking actually work?

I'm really hoping I'm wrong about this, but from what I can tell, GameKit hosted matchmaking simply does not work if a player invites some friends into a match but leaves some slots open for automatches. I can get each case to work individually, but when mixed, no one can connect.
Consider three players: A, B, and C. A invites B into the match and leaves a third slot open. C chooses to be matched into a three player game.
Now, when B processes the invite from A (by virtue of having registered an inviteHandler on GKMatchmaker), he contacts the hosting server to connect and sets his player ready state. Player A will then get a delegate message to matchmakerViewController:didReceiveAcceptFromHostedPlayer: saying that B has connected. In a two player game, B could at this point start the game and proceed. Instead, clicking the "Play Now" button causes the match-maker to wait for a third player to arrive.
Meanwhile Player C has chosen to be added to a match automatically. If A and B had also asked to be added automatically, all three would then be notified of the match via the delegate matchmakerViewController:didFindPlayers: method. Instead, however, clicking the "Play Now" button causes the match-maker to wait... forever. Player A is also waiting... forever. Player B knows only about the inviter, player A, so he could in theory try to start the game, but it would be pointless since A only knows about some of the participants.
It's hard for me to believe the system could have such a catastrophic flaw, but I've run this scenario, and traced all the delegate methods exposed in the relevant GameKit classes, and when the players get into their infinite-waiting state there are no delegate messages sent. It's as if GameCenter does not fully know about the existence of A and B, which would help explain why A has to explicitly mark B as present in the view controller despite obviously having been visible "enough" to have received the invite in the first place. I've also tried having player C request only a two-player game, on the idea that perhaps this meant that Player A counted as only one "visible" player.
Does anyone have any direct experience with this API, and can claim explicitly that it works (or doesn't) for this use case? This is a serious issue for me; this pretty much means that I have to throw away my GameKit-based matchmaking code and write something completely from scratch.
Thanks in advance for any information.

Where does game logic go in Rails apps?

(Disclosure: I'm very new to Rails)
I am trying to make a RISK-style board-game in Rails, though this question may apply for any MVC-style framework.
I have players and games. Players can join games until the game is full. Trying to join a full game (or the same game twice) signals an error, yada yada.
Below are three pieces of game logic that I am unsure where to place, or at least where they are typically placed.
If a game is full, it should start and do things related to that (ie, messaging all players that the game has begun, randomly disperse armies across the map).
When a player executes moves during his turn it seems reasonable to have that logic in the controller. What about when his turn ends and it is time to message the next player? Would that code go in the same controller as
Suppose that a player forfeits his turn if he does not finish it within 24 hours. I'd need to periodically look at all the games in my app and see if a player started a turn more than 24 hours ago. Where would this logic go?
My question is: Where does logic for items like the above go in a Rails/MVC app?
In one sense I could stuff all of it except 3. into the controllers for the last-done-action. For instance I could place the logic for 1. in the player-joins-game controller method (check if the game is full after every player join, if it is, commence 1. related logic). This seems like it might be the wrong place, but maybe that's how it is typically done.
Rails' convention is "fat model, thin controller". so I would suggest that the state of the game should be held by the Game model.
You webapp consists of zero or more games, and each game consists of 1 or more players.
The state of "full", or the state of "game begun" are properties of the game, and should be held by that model.
So for 1) When the final player joins (or perhaps, all current players vote to start the game), the game state (a property of Game) would be set to "begun", the property that holds the currently active player would be set, and a delayed job would be queued to message all the players.
For 2, the game has a "execute move" method in the Game controller that would check that the player executing the move is the current player, then it would execute the move against the Game model. The Game model internally would know if the move is valid, what the result is, and what the next step(s) would be. It would, again, use something like a delayed job to message the next player.
For #3, again, a delayed job could be set to execute the timeout. I'm not 100% on how to schedule delayed jobs, or if there's another gem/plugin that would work better. But, the job would call a method on the Game controller to check the status of the game at the required time. If the player has not moved, then execute your forfit logic, which would, again, be a method in the Game model.
The state of each player could be held in the Player model, or in the Game model, I suppose, depending on the game, and how much interaction between Player models there might be.
In the case of a risk game, I would think the player model would be rather thin, as the state of the board is more about which player owns a country, and how many armies they have there - that's more a state of the game, then a state of each individual player. I would expect the Player model in a risk game to be more oriented towards metadata about the actual player - username, wins/losses, skill level, etc.
In a game like Supremacy, where the player has resources, nukes, etc., then there's more data to store in the Player model.

Resources