feat(multiplayer): ENet networking + player/world sync + lobby menu + chat
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>
This commit is contained in:
63
scripts/net/PlayerSyncComponent.gd
Normal file
63
scripts/net/PlayerSyncComponent.gd
Normal file
@@ -0,0 +1,63 @@
|
||||
extends Node
|
||||
|
||||
@export var sync_rate: float = 0.05 # 20 Hz
|
||||
|
||||
var _owner_id: int = 1
|
||||
var _timer: float = 0.0
|
||||
|
||||
# Interpolation buffer for remote dolphins
|
||||
var _remote_pos: Vector3 = Vector3.ZERO
|
||||
var _remote_yaw: float = 0.0
|
||||
var _remote_pitch: float = 0.0
|
||||
var _has_remote_data: bool = false
|
||||
var _interp_speed: float = 12.0
|
||||
|
||||
|
||||
func setup(owner_peer_id: int) -> void:
|
||||
_owner_id = owner_peer_id
|
||||
set_multiplayer_authority(owner_peer_id)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if NetworkManager.is_solo():
|
||||
return
|
||||
|
||||
var parent_node := get_parent()
|
||||
if not is_instance_valid(parent_node):
|
||||
return
|
||||
|
||||
if multiplayer.get_unique_id() == _owner_id:
|
||||
# Send our transform at sync_rate
|
||||
_timer += delta
|
||||
if _timer >= sync_rate:
|
||||
_timer = 0.0
|
||||
var pos: Vector3 = parent_node.global_position
|
||||
var yaw: float = parent_node.rotation.y
|
||||
var pitch: float = 0.0
|
||||
if parent_node.has_node("CameraPivot"):
|
||||
pitch = parent_node.get_node("CameraPivot").rotation.x
|
||||
var boosting: bool = false
|
||||
if "is_boosting" in parent_node:
|
||||
boosting = parent_node.is_boosting
|
||||
receive_transform.rpc(pos, yaw, pitch, boosting)
|
||||
else:
|
||||
# Interpolate toward remote state
|
||||
if _has_remote_data:
|
||||
parent_node.global_position = parent_node.global_position.lerp(
|
||||
_remote_pos, _interp_speed * delta
|
||||
)
|
||||
parent_node.rotation.y = lerp_angle(parent_node.rotation.y, _remote_yaw, _interp_speed * delta)
|
||||
if parent_node.has_node("CameraPivot"):
|
||||
var pivot: Node3D = parent_node.get_node("CameraPivot")
|
||||
pivot.rotation.x = lerp_angle(pivot.rotation.x, _remote_pitch, _interp_speed * delta)
|
||||
|
||||
|
||||
@rpc("any_peer", "unreliable")
|
||||
func receive_transform(pos: Vector3, rot_yaw: float, rot_pitch: float, boost: bool) -> void:
|
||||
_remote_pos = pos
|
||||
_remote_yaw = rot_yaw
|
||||
_remote_pitch = rot_pitch
|
||||
_has_remote_data = true
|
||||
var parent_node := get_parent()
|
||||
if is_instance_valid(parent_node) and "is_boosting" in parent_node:
|
||||
parent_node.is_boosting = boost
|
||||
Reference in New Issue
Block a user