Add dedicated server / host / client modes via NetworkManager autoload, PlayerSyncComponent (20 Hz unreliable RPC), WorldSyncComponent (authoritative block break/place), ChatManager (F2), LobbyMenu scene, updated MainMenu with Solo/Heberger/Rejoindre/Quitter buttons. Port changed to 7777 (9999 occupied by sntlkeyssrvr on this machine). Mobs disabled in multi (spawn solo only). Solo mode untouched. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
75 lines
2.2 KiB
GDScript
75 lines
2.2 KiB
GDScript
extends Node
|
|
|
|
# Attached to ChunkManager node.
|
|
# Server: intercepts block changes and broadcasts to clients.
|
|
# Client: receives and applies block changes locally.
|
|
|
|
var _chunk_manager: Node = null
|
|
|
|
|
|
func _ready() -> void:
|
|
_chunk_manager = get_parent()
|
|
|
|
|
|
# Called by Main.gd instead of world.break_block / world.place_block when in multiplayer.
|
|
func server_break_block(world_pos: Vector3) -> int:
|
|
if not NetworkManager.is_server():
|
|
# Client sends request to server
|
|
request_break.rpc_id(1, world_pos)
|
|
return 0
|
|
var broken_id: int = _chunk_manager.break_block(world_pos)
|
|
if broken_id > 0:
|
|
broadcast_block_change.rpc(world_pos, 0)
|
|
return broken_id
|
|
|
|
|
|
func server_place_block(world_pos: Vector3, block_id: int) -> bool:
|
|
if not NetworkManager.is_server():
|
|
# Client sends request to server
|
|
request_place.rpc_id(1, world_pos, block_id)
|
|
return false
|
|
var placed: bool = _chunk_manager.place_block(world_pos, block_id)
|
|
if placed:
|
|
broadcast_block_change.rpc(world_pos, block_id)
|
|
return placed
|
|
|
|
|
|
@rpc("any_peer", "reliable")
|
|
func request_break(pos: Vector3) -> void:
|
|
if not NetworkManager.is_server():
|
|
return
|
|
var sender_id: int = multiplayer.get_remote_sender_id()
|
|
var broken_id: int = _chunk_manager.break_block(pos)
|
|
if broken_id > 0:
|
|
broadcast_block_change.rpc(pos, 0)
|
|
# Notify requesting peer of item pickup
|
|
notify_break_result.rpc_id(sender_id, broken_id)
|
|
|
|
|
|
@rpc("any_peer", "reliable")
|
|
func request_place(pos: Vector3, block_id: int) -> void:
|
|
if not NetworkManager.is_server():
|
|
return
|
|
var placed: bool = _chunk_manager.place_block(pos, block_id)
|
|
if placed:
|
|
broadcast_block_change.rpc(pos, block_id)
|
|
|
|
|
|
@rpc("authority", "call_local", "reliable")
|
|
func broadcast_block_change(world_pos: Vector3, new_id: int) -> void:
|
|
# Applied on all peers including server via call_local
|
|
if multiplayer.is_server():
|
|
return # already applied on server
|
|
if new_id == 0:
|
|
_chunk_manager.break_block(world_pos)
|
|
else:
|
|
_chunk_manager.place_block(world_pos, new_id)
|
|
|
|
|
|
@rpc("authority", "reliable")
|
|
func notify_break_result(broken_id: int) -> void:
|
|
# Signal to Main.gd to add item to local inventory
|
|
var main := get_tree().get_first_node_in_group("main")
|
|
if is_instance_valid(main) and main.has_method("_on_remote_block_broken"):
|
|
main._on_remote_block_broken(broken_id)
|