multyplayer

This commit is contained in:
algodoogle
2026-07-16 18:36:49 +01:00
parent 5e0b58a984
commit 1869dbf054
28 changed files with 974 additions and 60 deletions
+10 -5
View File
@@ -54,6 +54,12 @@ func _on_body_entered(body: Node3D) -> void:
if _combining or body == _item:
return
# Combining is a world-state change: only the server/offline host runs it.
# (Clients never have the base item snapped, so their zone won't monitor, but
# guard explicitly in case of overlap during authority handoff.)
if not NetworkManager.owns_world():
return
var other := _find_combinable(body)
if not other:
return
@@ -75,11 +81,9 @@ func _combine(other_body: Node3D, result: PackedScene) -> void:
_combining = false
return
# Spawn the result at the base item's location, in world space.
# Spawn the result (networked) at the base item's location, in world space.
var base_transform := _item.global_transform
var result_instance: Node3D = result.instantiate()
_item.get_tree().current_scene.add_child(result_instance)
result_instance.global_transform = base_transform
var result_instance := NetworkManager.spawn_item(result.resource_path, base_transform)
# Free the base item and consume the incoming item.
snap_zone.drop_object()
@@ -90,7 +94,8 @@ func _combine(other_body: Node3D, result: PackedScene) -> void:
other_body.queue_free()
# Snap the result into the now-empty zone.
snap_zone.pick_up_object(result_instance)
if result_instance:
snap_zone.pick_up_object(result_instance)
# Find a CombinableItem among the direct children of [param node].
+64
View File
@@ -0,0 +1,64 @@
class_name NetPickable
extends Node
## Networks an XRToolsPickable (RigidBody3D). Default authority is the server,
## which simulates free items and syncs their transform. Grabbing an item with a
## hand transfers authority to the grabbing client (its local kinematic grab
## driver then drives the synced transform); releasing returns authority and the
## throw velocity to the server. Non-authority peers keep the body frozen and
## follow the synced transform, so only one machine ever simulates an item.
@onready var _item: XRToolsPickable = get_parent() as XRToolsPickable
var net_held_by := 0 # peer id currently holding (0 = free); kept consistent via NetworkManager
var _was_authority := true
func _ready() -> void:
if not _item:
push_error("NetPickable must be a child of an XRToolsPickable")
return
_item.grabbed.connect(_on_grabbed)
_item.released.connect(_on_released)
_was_authority = _item.is_multiplayer_authority()
_apply_authority_state()
func _physics_process(_delta: float) -> void:
if not NetworkManager.is_online():
return
var mine := _item.is_multiplayer_authority()
if mine != _was_authority:
_was_authority = mine
_apply_authority_state()
# Configure physics for whether we own this item or merely mirror it.
func _apply_authority_state() -> void:
if not _item:
return
if _item.is_multiplayer_authority():
# We own physics: simulate the item whenever it is not held.
if not _item.is_picked_up():
_item.freeze = false
else:
# Someone else owns it: follow the synced transform kinematically.
_item.freeze = true
_item.freeze_mode = RigidBody3D.FREEZE_MODE_KINEMATIC
func _on_grabbed(_pickable: Node3D, by: Node3D) -> void:
if not NetworkManager.is_online():
return
# Only hand grabs transfer authority; snap-zone grabs are server-driven.
if not (by is XRToolsFunctionPickup):
return
NetworkManager.request_item_authority.rpc_id(1, _item.get_path())
func _on_released(_pickable: Node3D, by: Node3D) -> void:
if not NetworkManager.is_online():
return
if not (by is XRToolsFunctionPickup):
return
NetworkManager.release_item_authority.rpc_id(1, _item.get_path(), _item.linear_velocity, _item.angular_velocity)
+1
View File
@@ -0,0 +1 @@
uid://6n784li8n5ck