Simplified Network manager WIP

This commit is contained in:
JonShard
2026-07-29 13:41:16 +02:00
parent 0f1f0c6a93
commit 6933e17f3a
15 changed files with 299 additions and 195 deletions
-10
View File
@@ -1,10 +0,0 @@
extends MultiplayerSpawner
func _ready() -> void:
add_spawnable_scene("res://Stations/csg_box_3d.tscn")
func _process(delta: float) -> void:
pass
-1
View File
@@ -1 +0,0 @@
uid://ctsqvhicswj8m
+3 -3
View File
@@ -6,15 +6,15 @@ const GAME_MANAGER = preload("res://scripts/game_manager.gd")
var xr_interface :XRInterface
func _ready():
print("main: _ready")
print("Main _ready")
RECIPE_MANAGER.print_all_recipes()
GAME_MANAGER.meals_in_play = ["hamburger"]
xr_interface = XRServer.find_interface("OpenXR")
if xr_interface and xr_interface.is_initialized():
print("OpenXR started :)")
print("Main OpenXR started :)")
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
get_viewport().use_xr = true
else:
print("OpenXR failed to start. Check your headset...")
print("Main OpenXR failed to start. Check your headset...")
+169
View File
@@ -0,0 +1,169 @@
extends Node
const DEFAULT_PORT := 24565
const MAX_CLIENTS := 7
signal player_joined(peer_id: int)
signal player_left(peer_id: int)
signal session_started(is_server: bool)
signal session_ended()
signal connection_failed()
# World hooks, registered by main.gd once the scene tree exists.
var _world: Node = null
var _players_spawner: MultiplayerSpawner = null
var _items_spawner: MultiplayerSpawner = null
var _content_root: Node = null
func _ready() -> void:
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
multiplayer.connected_to_server.connect(_on_connected_to_server)
multiplayer.connection_failed.connect(_on_connection_failed)
multiplayer.server_disconnected.connect(_on_server_disconnected)
_handle_cmdline()
# --- Public API ------------------------------------------------------------
## Start hosting. The host is peer 1 and also plays (listen server).
func host(port: int = DEFAULT_PORT) -> Error:
var peer := ENetMultiplayerPeer.new()
var err := peer.create_server(port, MAX_CLIENTS)
if err != OK:
print("NetworkManager HOST failed to create_server on port %d: %s" % [port, error_string(err)])
return err
multiplayer.multiplayer_peer = peer
print("NetworkManager HOST started on port %d (peer id %d)" % [port, multiplayer.get_unique_id()])
session_started.emit(true)
return OK
## Join an existing host.
func join(address: String = "127.0.0.1", port: int = DEFAULT_PORT) -> Error:
var peer := ENetMultiplayerPeer.new()
var err := peer.create_client(address, port)
if err != OK:
print("NetworkManager JOIN failed to create_client %s:%d: %s" % [address, port, error_string(err)])
return err
multiplayer.multiplayer_peer = peer
print("NetworkManager JOIN connecting to %s:%d ..." % [address, port])
return OK
## Leave the session and tear down transport.
func leave() -> void:
_go_offline()
print("NetworkManager Session ended")
session_ended.emit()
# Restore Godot's default OfflineMultiplayerPeer (rather than leaving the peer
# null), so is_multiplayer_authority()/get_unique_id() keep working while we are
# back in single-player / menu state.
func _go_offline() -> void:
if multiplayer.multiplayer_peer:
multiplayer.multiplayer_peer.close()
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
unregister_world()
func is_server() -> bool:
return is_online() and multiplayer.is_server()
## True only when a real ENet session is active. Godot installs a default
## OfflineMultiplayerPeer, so a non-null peer alone does not mean "online".
func is_online() -> bool:
var p := multiplayer.multiplayer_peer
return p != null and not (p is OfflineMultiplayerPeer)
## True on the machine that owns authoritative world logic: the server when
## online, or the single player when offline. Station logic and spawning should
## only run where this is true, so state has one source of truth.
func owns_world() -> bool:
return not is_online() or is_server()
# --- Station work-progress seam -------------------------------------------
## Reusable entry point for a client to contribute work to a station (e.g. a
## future chopping/gesture station). The client detects the gesture locally and
## calls this; the server validates and accumulates. Timer-driven stations like
## the Hob don't need it, but it is the drop-in seam for input-driven ones.
@rpc("any_peer", "reliable")
func submit_work(station_path: NodePath, amount: float) -> void:
if not is_server():
return
var station := get_node_or_null(station_path)
if station and station.has_method("add_work"):
print("NetworkManager submit_work: peer %d contributed %.2f to %s" % [multiplayer.get_remote_sender_id(), amount, station.name])
station.add_work(multiplayer.get_remote_sender_id(), amount)
## Called by the world scene once it's ready, passing its spawners. Must run
## before world_ready()/host()/join() on every peer so the custom spawn
## function is installed before any spawn packet can arrive.
func register_world(world: Node, players_spawner: MultiplayerSpawner, items_spawner: MultiplayerSpawner) -> void:
_world = world
_players_spawner = players_spawner
_items_spawner = items_spawner
_content_root = items_spawner.get_node(items_spawner.spawn_path) if items_spawner else world
print("NetworkManager World registered (players_spawner=%s items_spawner=%s)" % [str(players_spawner != null), str(items_spawner != null)])
## Called when the world scene goes away (disconnect, leaving the session) so
## the autoload doesn't hold stale/freed references across a scene reload.
func unregister_world() -> void:
_world = null
_content_root = null
_players_spawner = null
_items_spawner = null
# --- Session signal handlers ----------------------------------------------
func _on_peer_connected(peer_id: int) -> void:
print("NetworkManager peer_connected: %d" % peer_id)
# Only the server reacts by materialising that peer's player.
if is_server():
print("NetworkManager player_present: %d" % peer_id)
player_joined.emit(peer_id)
func _on_peer_disconnected(peer_id: int) -> void:
print("NetworkManager peer_disconnected: %d" % peer_id)
if is_server():
print("NetworkManager player_absent: %d" % peer_id)
player_left.emit(peer_id)
func _on_connected_to_server() -> void:
print("NetworkManager connected_to_server (my id=%d)" % multiplayer.get_unique_id())
session_started.emit(false)
func _on_connection_failed() -> void:
print("NetworkManager connection_failed")
_go_offline()
connection_failed.emit()
func _on_server_disconnected() -> void:
print("NetworkManager server_disconnected")
_go_offline()
session_ended.emit()
# --- Command-line driven test bootstrap -----------------------------------
func _handle_cmdline() -> void:
var args := OS.get_cmdline_user_args()
if args.has("--server"):
print("NetworkManager cmdline: --server")
host()
elif args.has("--join"):
var idx := args.find("--join")
var addr := "127.0.0.1"
if idx + 1 < args.size():
addr = args[idx + 1]
print("NetworkManager cmdline: --join %s" % addr)
join(addr)
+1
View File
@@ -0,0 +1 @@
uid://da1xwj5tyeii6