I coded a bomberman application that uses a gamekit peer to peer connection. The problem is that after a while the game isn't in sync anymore.
I looked at the sample code for GKTanks and used their model. There is no client/server relation between peers so I didn't use one in my game. Both peers maintain a gamestate which they update based on received data.
I have a NSTimer that's used for running the gameloop at each frame. The NSTimers aren't in sync so sometimes the gamestates become different ex: players pick up a powerup at approximately the same time and they both get the powerup because it takes a while to send data.
I would appreciate any idea on making the app work. I'm thinking of rewriting the code to use client-server but I'm not sure if it's a good idea... yet
Thank you!
EDIT: I changed the code such that a random player is picked to be the host.
Every time a player places a bomb he asks the server where to place it. The server returns the players position(as seen on the server) and then tells the player where to place the bomb.
For powerups the server checks if a player picked up a powerup and if he did it sends a packet informing him.
Another problem has appeared now. The latency between devices is high(I'm using a bluetooth connection). It takes around 0.2 seconds to place a bomb after the client tapped the button to place it.
I'm sending all data reliably. Am I doing this right?
Well preferbly you want a host-client relationship where only the host can manipulate the game state, so in your case it would be:
Both players rush to the powerup.
Host picks it up first.
It gets registered and the host recieves the power-up.
Meanwhile player#2 also picks up the power-up, sends the action to the host.
The host informs player#2 that the power-up is already disappeared.
The thing with your situation you are bound to get desynchs from packet loss.
With host-client relationship that cannot happen, the only problem is the host always has an advantage that becomes greater when the latency increases between devices especially on smartphones.
In a game like bomberman it's perfectly plausible to send the entire gamestate each time something changes instead of the action that was performed, this is to ensure both devices are in sync.
To sum it up: both users have their gamestate but only the host can manipulate both.
what you should do:
one of the devices is host, another one is client
host process all the game states and makes decisions, then it sends whole gamestate to the client
client gets the gamestate and just draws everything based on it - it doesnt make any decisions (who picked bomb, did bomb exploded etc)
client just sends input to the host (pressed left,right, pause etc)
that's it. if you try to make decisions on both machines, you will run into big troubles trying to keep them in sync.
Related
im making a multiplayer FPS game, and I have pretty much all the networking done and working. The issue is, that photon is syncing to players local movement, but if u have a bad connection, you could not tell it is happening cause player send late updates to the server and you can see other players lagging but you can move free and smoothly.
Im aware a lot of games work this way but i also know there are games like medal of honor that your player get stock in the last place every one else saw you. I need to know how to implement this on my game, because gameplay depends on it.
What you describe is "local prediction" of actions / movement.
If I understand this right, you want clients to not act or move if there wasn't a confirmation? If so, you'd need an authoritative host or server. You'd always wait for a confirmation from the host to move the player in any way.
But .. this is not going to work well. Players will feel the lag very much and this is annoying.
You probably want to predict the movement, then correct the local situation if the server disagrees.
I would recommend using Fusion instead of PUN for shooters. It can be run with host and has a nice API to reconcile the actual state from prediction to what the host simulated.
I'm trying to understand how to call events between client and server. My goal for now is simple. I want to create anything that is interactable for 2 players.
Easiest thing I could think of was cube that is switching color when clicked. So I did create actor based blueprint, checked "Replicates" and AlwaysRelevant to be sure. PlayerController is also replicated and there is no pawn needed.
Color change blueprint:
SM is just static mesh if that is important. As far as I know client have no authority to call multicast events so I wanted to push it through server but it stops there. Called from server works as expected and color itself IS replicated to client, however client cannot change color himself.
What am I missing in this concept? I've watched like 5 videos about replication and I started to think there is something missing which is either obvious for everyone but me or their examples do not need things I do here.
As you've found out, a player's client can not directly call server RPCs on actors which the player does not own. Calls must be routed through that player's PlayerController. The server copy of the player's PlayerController can then call server methods on server-owned actors.
Another issue is that you seem to be using both RPCs and replicated properties for the same purpose. Unclear to me why changed is replicated since you're modifying it in a multicast event which normally runs on all the machines. This is a recipe for hard to find race condition bugs.
Replication in Unreal is definitely one of the harder concepts to get the hang of. The resource that helped me the most is this guide which while quite dated, is both comprehensive and to the point.
You can't have it in PlayerController, it's got to be in a Pawn, or if not, in PlayerState, or it won't get shared to other clients.
I have managed to sync my ridigbodies real good but I just noticed that when a client (that's not the master) collides with one it doesn't move, it's locked, while reading on the net I had an idea when the object collides with a rigidbody I just transfer the ownership of that object to that client for the moment for this client to process the collision (I have tested this and it works really good, both clients sync perfectly)
is this recommended? performance-wise and security/cheating wise?
Thanks!
Short answer:
Transferring ownership of a GameObject to a client, when that client needs to control and update the object data, is fine. In cases of detecting cheating possibilities, always have one client (typically the master client or a dedicated server) validate, correct and sync the data to all clients.
I will not make any assumptions. Based on your explanation of the issue, it seems your GameObject Rigidbody IsKinematic was not being synced, causing the collisions having different effects at each client end. But in case that might not be the issue, I have a longer answer hoping it might help for this or other scenarios.
Longer version:
Sync Rigidibody data over the network where it is fundamentally required to be present on the client GameObject. The rest of the Rigidbody data can be created / calculated / simulated on each client individually:
This way, you will make sure all parameters of that Rigidbody are correct (e.g. isKinematic is correctly enabled/disabled on all clients)
Your games will always have the minimum required data to create/simulate the rest of the events and effects properly, reducing network lags and improving performance.
Where data validation is required, the master client will always validate the non-master client data, makes the crucial adjustments and decisions and updates the room data for all clients where necessary. This reduces the chances of players cheating.
Developers will find bugs easier when the events that are supposed to take place on each client, do not align with what is expected. This shows itself more often in scenarios where several events should take place at the same time and on each client.
Much longer version:
When I use PUN2 on GameObjects in my games, I only sync Rigidbody where those GameObjects require Rigidbody values to be present on the clients during collisions to perform specific tasks (e.g. using the velocity or direction for dynamic sound/visual effects), or when the master is validating and correcting the data needed for the non-master clients (as a result of network delay or cheat/hack tampering the data on client side).
When using PUN2 (up to this date), I update its class internal code to my needs. For example, PhotonRigidbodyView does not sync the kinematic state of a Rigidbody yet. When I need this in my games, I could override the class with my CustomPhotonRigidbodyView class (and/or updating the PhotonRigidbodyView a bit).
Does it effect the performance when using PhotonRigidbodyView? Yes, when not used with care, it does decrease it when there are too many objects syncing over the network at the same time. The clients will see jagged movements.
Does it allow cheaters to take advantage of this data, manipulate it and send it over to the clients? Yes, if the game is vulnerable to basic cheats. Then again, the topic of security/cheat detection is quite vast, so for each game definition of "basic" cheats are different.
Is it a good idea to transfer ownership momentarily to be processed on client side? Yes in some cases, other cases no:
If doing this momentary transfer is the only place you do this and it solves all your problems (except cheating), then use it so you won't spend too much time fixing this one part in a different way.
If the Rigidbody or Transform data is being validated and/or synced, either constantly or in periodic intervals by one client (to prevent cheating or to sync client data properly at crucial times), then it is fine to transfer momentarily too.
I typically transfer ownership, when the object data must be changed by the client (e.g. grabbing / dragging around / shooting / throwing) and once the action is performed, ownership will be back to the master to be validated and synced for all clients (including the one that just transferred the ownership). This results in more time spent on testing, catching unwanted (possibly unseen) bugs, and reduced cheating possibilities.
In case a developer working on your game has not properly optimized the Collider and/or Rigidbody components for each GameObject yet, please make sure you have done so before syncing their data over the network. This page in Unity doc may be a good reference to check whether your GameObjects need to be static colliders or dynamic colliders:
https://docs.unity3d.com/Manual/class-Rigidbody.html
https://docs.unity3d.com/Manual/CollidersOverview.html
Once the GameObjects that need a Rigidbody component are identified, then you can decide which ones need to be fully synced over the network or partially synced and/or their ownership transferred when required.
I hope my answer does not confuse any of the readers. If there is anything not clear, please mention in the comment and I will improve my answer for you.
Update: 2019-05-10 (reply to the 2nd comment):
For a pool game involving so many GameObjects, I would not transfer the ownership of all objects to a client. I would:
Create a struct holding the necessary information such as:
ball_id: indicating which ball is being hit by the pool stick
hit_info: a Vector3 representing the position (on the ball surface) and direction of the hit applied to the ball, by the hit stick.
hit_force: the required force to apply to the Rigidbody of the ball that is being hit by the hit stick.
and any other information that I might need, when the player hits the ball with stick.
I can then combine this information and pass them to the AddForceAtPosition method of the Rigidbody of the ball.
Dispatch this struct in the room, for all the clients to receive.
Once each client receives this message, including the sender, (in OnEvent as EventData containing the Phton Event Data), it will apply this info to the correct ball and will create its own version of physics (small differences will be noticed between each client).
This way:
I have the minimum amount of information passed over the network to make the simulations happen on all clients
Improved performance of the game by avoiding parsing and applying unnecessary Rigidbody data
Reduced the cheating possibilities of a client moving any of the other balls that they are not supposed to, around the table or into the pots.
To increase security as well as making sure the balls on all clients are exactly where they are supposed to be, another struct will be dispatched for example by the master client, indicating the exact position (and rotation) of each ball on the pool table (or in the pot).
I would sync the ball positions periodically (either at pre-defined intervals or at specific moments of my choosing depending on the game state) to all clients to overcome any incorrect positions at any moment in the game. This periodic sync can be done by the master client or a dedicated server.
What I'm trying to make
Hi, game development newbie here. The game I am trying to make is fairly simple. It's almost exactly like the old FC game "Ballon Fight" except that I'm trying to make it online where players can go through a match making to find opponents.
BalloonFight:
What I Read
I have read some articles, and found most of them lead to two approaches:
Put all game logic on the client, and the client sends player inputs to server on every frame update. The server acts like a dispatcher which only makes sure player A's input is received by both client A and B. My understanding is that if we see the client in this case as a pure function, and if the two players' inputs are received by each other, the game should produce same results on both clients. Thus synchronization is achieved.
Put all game logic on the server, and let the server do the calculations and send back results to both clients. In this case, clients only worry about displaying.
My Fears
Solution 1 sounded like a simpler one to me, but immediately I realized when network problem is put into account, it becomes incredibly complicated. Losing player A's connection for a few seconds means all the input is lost in that period. What I can guess is, to counter that, the server has to detect whether player A is lagged out and accumulate input from player B until player A is back then feed all the accumulated input to player A's client. Player A's client then need to do a fast forward to catch up. This sounds like there's huge amount of infra work on both client side and server side.
Solution 2 on the other hand looks very daunting to me, since for now I have only written some games on the client side.
My questions
in order to make a simple online game like this, what is the most beginner friendly way to synchronize game state?
if I were to use solution 1 stated above, is there any framework that provides such infra so that I don't have to handle network issues all by myself?
In advance, thank you game dev gurus.
I have made a game (is still in Beta, need improvements, and other things), and I would like to know if exists a better approach of what I have done in my game servers. (Programmed on C#)
The process to play a game is something like this:
Client application (player) → connect to lobby server → check for an available room with the game he likes to play → the lobby answer the request and point the player to right game server (all using "raw" TCP/sockets).
Each game server automatically start the game when exists at least 4 players in the room (multiple rooms are possible) and a maximum of 12. Each room is launched in a different thread, I mean, I create one thread per room (4-12 players), so if I have 1.200 (many more can be expected by game server) then will be at least 100 threads (even more depending of how many players are really in each room).
The main thread (and is work) plus all the threads created will be consuming all resources in my server... so, I was wondering if anybody can suggest a better idea or approach?
Keep in mine that all the connections are asynchronous, except in the room, I mean, in the room the server must wait for the move of one player (like a Ludo game or a bet) to let the next player (in the room) do the same. In fact, the buttons to make a move are enabled only to the player that is turn to move on. For that reason the transmission in place is synchronous and when somebody move the rest receive their respective notifications.
If you can wait on multiple sockets in the same thread (that I don't know and it's probably OS-specific) and you can unambiguously associate incoming data with a particular socket (this you should be able to, I think), then you can service all rooms (or just a few) sequentially in the same thread and thus save on per-thread data structures in the OS and the per-thread stack. You will likely need to implement some kind of a state machine to achieve that and rearchitect your data structures.
Coming from a MUD development background, the usual process for this kind of thing is to work on a "heartbeat" model:
You have a timer thread, which fires a heartbeat event/message at regular intervals.
With each heartbeat, a subscribed reader-thread checks all the connected sockets to see if they have any data to read. If so, the commands (button presses, etc) can be put in a queue (along with an indicator of which user, room, etc) to be read by the main game processor.
Game processor simply processes messages from the incoming queue, and produces responses (which can be put on an outgoing queue for delivery, if you fancy it).
This is how I've always done it when writing chat servers, talkers, and MUDs, and sounds like it could be a good fit for your requirements too.
HTH