GrapeSodaGames / Multiplayer

0 stars 0 forks source link

Refactor Multiplayer Networking Logic #142

Closed zaphodb2002 closed 6 months ago

zaphodb2002 commented 6 months ago

This issue will serve as the overview of a complete rework of the networking logic. See #140 for the long saga of me learning how to do any of this.

What I'd really like to do is to strip down the multiplayer stuff to be as simple as possible. I spend a lot of time refactoring things into separate nodes and that might not be serving me well here. Simplify, and add lightness.

zaphodb2002 commented 6 months ago

Alright, let's see what we can do as far as a game plan.

Here's the two official examples from godot:

Pong Bomber

Here's a plugin that attempts to handle the multiplayer in a way that is very similar to what I've been trying to do:

Multiplay Core

Let's start with the official examples and see if we can succinctly understand and communicate how it works.

zaphodb2002 commented 6 months ago

Pong

No Autoloads Lobby scene is loaded first lobby.gd extends Control, handles connection logic

lobby.gd

_ready() :

bounce() @rpc("any_peer", "call_local")

paddle.gd

This is the player logic for the paddle object, handles input and movement

Exports

player number

_process()

set_pos_and_motion() @rpc("unreliable")

_on_paddle_area_enter()

zaphodb2002 commented 6 months ago

Thoughts:

This solution does not use MultiplayerSpawner or MultiplayerSynchronizer nodes. This surprises me because I thought that's how we're supposed to be doing it now. There was a blog post I was working off of in #140, I gotta go find that and compare. It's entirely likely that this example wasn't really redone for 4.0 paradigms, just updated to work.

zaphodb2002 commented 6 months ago

Bomber

Okay good, this one uses the node based solution.

Autoloads

gamestate.gd

This is the global object for the state of the game. Handles mp connectivity stuff like lobby.gd did in the Pong example, but here it's more elegantly abstracted. There is a player list that requires registering and unregistering the players. Also manages starting and ending the game.

callback _player_connected(id)

register_player() @rpc("any_peer")

host_game()

join_game()

begin_game()

load_world() @rpc("call_local"):

lobby.gd

This handles just the UI management, and outsources the actual mp work to the gamestate via gamestate.host_game() or gamestate.join_game() and receiving signals from said gamestate when its status changes. There is literally no MP specific code in here.

player.gd

player logic, extends CharacterBody2D scene contains a child MPSync node, which is configured to replicate player:synced_position scene also contains a Node with player_controls.gd attached and another MPSync node below that for handling input authority

Exports

synced_position: Vector2 stunned: bool

_ready():

_physics_process()

zaphodb2002 commented 6 months ago

Thoughts:

This is much more in line with what I want to do. I think probably what we should do is scrap and replace what we have. I can bring over what I can but we need to really reduce the garbage here.

zaphodb2002 commented 6 months ago

I've spent some time creating a new GameState autoload like what the Bomber example has. Going to require quite a bit of changes.

zaphodb2002 commented 6 months ago

Okay, I think we're pretty much there. As it stands, the player list is getting populated correctly, the authority is getting set correctly (thanks to the MultiplayerSpawner.spawn_function callable) and it is syncing the requested info back and forth. Now we need to rework the UI.