Open ihhub opened 4 years ago
Should network be handled by SDL ? or something else ? seems like SDL_net is super old
We shouldn't rely on SDL for this case. We need to find a solution with extra dependencies: portable and OS independent.
The implementation must go in 2 stages: first stage should mimic messaging system through logging, while the second one will include real network connection code. We could create a separate tool to simulate certain events.
cc @oleg-derevenetz @ihhub Here's what I have in mind after thinking about it.
Indeed for netplay we will need to have an event system. For instance, currently if I go into my hero's army, and I split troops, the game directly changes the army instance and that's it. I'm guessing that with multiplayer, we want that when I do this, the game sends an event to the player acting as server, and server broadcast this as an incoming event to all other players (including initial player who initiated the split). In this system, the click on the "split" button will not be what is changing the army object instance, but it will be the fact that we receive an event telling us "split the army". Processing incoming events could be viewed from the game engine as a synchronous event loop that could be run at the same time as when we call the usual localEvent.handle() loop. It would just execute any command that is received, basically all the time. There could be of course checks on the client but probably this can be handled on case by case basis (for instance, what if I receive an event that the opponent user is splitting his troops, when it's my turn ? not possible normally)
Using this system, we have the benefit that:
WDYT ?
Hi @vincent-grosbois AFAIK this is not how multiplayer works in HoMM family. What is done is basically each player shares the state at the end of his turn (except for some exceptions like positions of heroes, maybe states of some objects visible to other players and multi-player battles), there is no communications in real-time in general, at least regarding such things like troops splitting, etc.
Thanks! I was wondering indeed how it was working for HoMM games. There must be some form of communication in "real time" at some point, because you can still see the opponent move during his turn , and for battles.
But indeed I don't know if the client receives all the "game state" info at each event, for all players. For instance if the opponent changes his army and that's it, maybe this info is only shared at the end of the turn to everyone. The only problem I see with this approach is that it's much more complex to implement, and I'm not sure what it brings, besides sending all the opponent state to the client (which is only a problem if someone wants to cheat for instance)
In what I'm proposing, there is no "real time" component in particular, it's still based on sequential event processing that updates the game state. There's no specific risk associated with losing events, at least no more than in the other version
Hi @vincent-grosbois AFAIK this is not how multiplayer works in HoMM family. What is done is basically each player shares the state at the end of his turn (except for some exceptions like positions of heroes, maybe states of some objects visible to other players and multi-player battles), there is no communications in real-time in general, at least regarding such things like troops splitting, etc.
The original games are probably not concerned with some players cheating, as the code was in full control of the original developers. With the open source setup, I fear, this can become a major concern. To solve it, one probably needs to run all the logic on a (trusted) server and clients should be only responsible for collecting player's Input and rendering the current state in response to commands from the server.
That's a good point, I ´d love to know the official stance on this. IMO we should really not care about this especially for a first version. Also note that the "server" will also run on a player's machine so it's not trusted either. Regardless addding protection against cheat still works in my proposal, it just means that there would be lots of rules to check between the moment the event is sent (from player) and when it's broadcast to other players to update the game state
Envoyé de mon iPhone
Le 8 déc. 2021 à 17:36, a1exsh @.***> a écrit :
Hi @vincent-grosbois AFAIK this is not how multiplayer works in HoMM family. What is done is basically each player shares the state at the end of his turn (except for some exceptions like positions of heroes, maybe states of some objects visible to other players and multi-player battles), there is no communications in real-time in general, at least regarding such things like troops splitting, etc.
The original games are probably not concerned with some players cheating, as the code was in full control of the original developers. With the open source setup, I fear, this can become a major concern. To solve it, one probably needs to run all the logic on a (trusted) server and clients should be only responsible for collecting player's Input and rendering the current state in response to commands from the server.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android.
Also note that the "server" will also run on a player's machine so it's not trusted either.
If it runs on one the player's machines — yes. That's why I mentioned trusted server. Technically it doesn't have to run on any of players' hosts, though that's the most convenient probably.
We shouldn't send small player events to other players. Army splitting, artifact sorting or internal hero updates must be done at least in one event. For example (very abstract code):
- open hero dialog
- remember the state of a hero
- do something by a player
- close hero dialog
- compare the current state of hero with initial. If different then send an event.
Even here we might not even send any events to other players. We need to send the state of a hero only at the end of a turn or before a battle with other player.
I don't think that we need any asynchronous code for this, generating events is substantially lightweight operation.
Regarding cheating: I was thinking about this and since it's an open source project it's really hard to prevent cheaters. For now it's not the biggest issue :)
OK I see
I think it really depends what you have in mind. In my version, the regular game state becomes fully controlled by an event loop, even for single-player games. It becomes closer to Model-View-Controller. Example:
- open hero dialog
- user splits troops
- army instance is not updated
- we send an event to the queue changing the army state
- army instance is still not updated
- during the next call to localEvent.handleEvent(), we poll all incoming events
- amongs the incoming events, there is a "change army" event
- this events trigger the change to the army instance data
- UI etc will reflect this automatically
Here it has the advantages that once the game is put in this form, then it's seamless to go from single player (queues message are in a vector somewhere in the process) to multiplayer (queue messages are dispatched on the network). It's still synchronous, but event-based.
In your proposal, it seems that the logic is still executed directly by the engine (eg : I split troops, the army instance is modified in the next instruction), but there is also state management that will have to happen through the network (eg, I receive events that tell me I need to change the game state). I guess this can work because the game is turned-based but I'm wondering if this approach is so clean. Isn't there potentially cases where you locally changed things, but at the same time receive external events that conflict with your previous changed? It seems like we need to fully understand all the use cases to be sure the whole game can fit this pattern
Here is a link to a PR that represents what I think you have in mind @ihhub : https://github.com/ihhub/fheroes2/compare/master...vincent-grosbois:gameevent?expand=1
Basically I'm emitting a new "set hero state" event each time the Hero dialog window is closed. Note that this can create already lots of useless events, for instance if you keep clicking "next hero" and not changing anything.
This new "set hero state" event is just sent and received in local mode. In real network mode, it would be sent to the server, and the server would send it back to all the other clients (I guess), and the other clients would actually apply the changes to the game state.
NB : in real network mode, the "game event" data sent over the wire would probably contain more metadata, such as who emitted the event, the timestamp and a "previous state" nonce so that the receiver could attest that indeed everyone is synchronised
Some basic simultaneous turn support like it Age of Wonders would be great, otherwise multiplayer with many people takes a long time for each turn.
+1 for simultaneous turns support, Age of Wonders-style. It makes coop games vs AI with a large number of human players a lot more palatable, among other things. It's even better if you have a setting to allow players of a same team to take turns simultaneously, but other teams still have to wait for their turn: it removes the twitch reflexes aspect while saving a lot of time in team games.
Some settings to allow other players to watch battles (all of them, or those of allies plus those whose location you have line of sight on) also help a lot to alleviate boredom.
The best would be to provide the full gamut of "live" turn-based (you see other players moving around), "play-by-mail" style (finish your turn and submit it to the server, which notifies the next player), and simultaneous (within teams, or everyone at the same time).
In short, there's the potential to give fheroes2 first-class multiplayer capabilities similar to recent Age of Wonders games, not just a clone of what was present in Heroes 2 at the time.
For instance, currently if I go into my hero's army, and I split troops, the game directly changes the army instance and that's it. I'm guessing that with multiplayer, we want that when I do this, the game sends an event to the player acting as server, and server broadcast this as an incoming event to all other players (including initial player who initiated the split). In this system, the click on the "split" button will not be what is changing the army object instance, but it will be the fact that we receive an event telling us "split the army".
This would introduce a very annoying lag, e.g. if there is a round-trip between me and the server of 100ms, every click will not change local state instantly (basic calculation like splitting is faster than redrawing a frame), but with a noticeable delay.
Event log is a good concept, but there is no need to wait for the confirmation from the server to apply an event you just generated if you know that it is your turn. The only edge case is when the timer runs out and you need to rollback the last actions that were not delivered to the server in time.
Architecture design document can be found here.