#Sync Multiplayer Interactions

13 messages · Page 1 of 1 (latest)

wheat lion
#

I managed to create a simple multiplayer shooter after following a tutorial.

I can sync player movements, shooting, and playing gun effects across all clients, but for some reason I can't seem to get my own interaction script working.

I only just started getting some errors regarding the multiplayer. Perhaps it has something to do with that?

#

Here is the code I have for an area3d attached to the player. It tracks when the player is touching something interactable:



@onready var collider_box = $CollisionShape3D2
@onready var name_text_label = $CanvasLayer/HoverText/MarginContainer/VBoxContainer/name_text
@onready var description_text_label = $CanvasLayer/HoverText/MarginContainer/VBoxContainer/description_text
@onready var hover_box = $CanvasLayer/HoverText
var name_text: String
var desc_text: String
var interactable_area: Area3D



#called by area_entered
func add_interactable(area: Area3D):
    if interactable_area == null:
        
        interactable_area = area
        if is_multiplayer_authority():
            name_text = area.get_hover_name()
            desc_text = area.get_hover_description()
            
            name_text_label.text = name_text
            description_text_label.text = desc_text
            
            hover_box.show()

#called by area_exited
func remove_interactable(area: Area3D):
    if interactable_area == area:
        hover_box.hide()
        name_text_label.text = ""
        description_text_label.text = ""
        
        interactable_area = null

#triggered by player
func trigger_interactable():
    if interactable_area != null:
        interactable_area.activate_trigger()



#

Finally, here is the player code that triggers this.

        attempt_trigger()```

and

```@rpc("call_local")
func attempt_trigger():
    #if interactRaycast.is_colliding():
    #        var hit_object = interactRaycast.get_collider()
    #        hit_object.activate_trigger()
    interactionArea.trigger_interactable()```
lavish cedar
#

Okay, without looking at your player script as a whole it'll be hard to tell whats going on there exactly. The attempt trigger is called incorrectly. If you want to call an rpc function your need to call it like this: func attempt_trigger.rpc() otherwise it will just be called on the players machine.

#

when you check for if is_multiplayer_authority():, you need to also make sure that the local object is set to the correct authority.

#

Like in your player script you likely set the multiplayer authority when the player spawns in as the peer_id. Then in the process function when you check whetheror not it is the authority, it compares it against the peer id of that machine.

#

So that the instantiated player of lets say plaer 333373 is only processed by player 333373 instead of anyone else. The changes are then distributed across the network with the MultiplayerSynchronizer

wheat lion
#

Here's the first half of the player code


signal health_changed(health_value)

@onready var camera = $Camera3D
@onready var anim_player = $AnimationPlayer
@onready var muzzle_flash = $Camera3D/Pistol/MuzzleFlash
@onready var raycast = $Camera3D/RayCast3D
@onready var interactRaycast = $Camera3D/InteractionRayCast
@onready var interactionArea = $InteractionArea

var health = 3

@export var SENSITIVITY: float
@export var SPEED: float
@export var JUMP_VELOCITY:float
@export var weapon_sway:bool


# Get the gravity from the project settings to be synced with RigidBody nodes.
@export var gravity: float = 20

func _enter_tree():
    set_multiplayer_authority(str(name).to_int())

func _ready():
    if not is_multiplayer_authority(): return
    
    Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
    camera.current = true

func _unhandled_input(event):
    if not is_multiplayer_authority(): return
    
    if event is InputEventMouseMotion:
        rotate_y(deg_to_rad(-event.relative.x * SENSITIVITY))
        camera.rotate_x(deg_to_rad(-event.relative.y * SENSITIVITY))
        camera.rotation.x = clamp(camera.rotation.x, -PI/2, PI/2)
        
    if Input.is_action_just_pressed("shoot") \
            and anim_player.current_animation != "shoot":
        play_shoot_effects.rpc()
        
        if raycast.is_colliding():
            var hit_player = raycast.get_collider()
            hit_player.receive_damage.rpc_id(hit_player.get_multiplayer_authority())
            
    if Input.is_action_just_pressed("toggle_sway"):
        weapon_sway = !weapon_sway
        if weapon_sway == false:
            anim_player.stop()
            
    if Input.is_action_just_pressed("interact"):
        attempt_trigger.rpc()
#
    if not is_multiplayer_authority(): return
    
    # Add the gravity.
    if not is_on_floor():
        velocity.y -= gravity * delta

    # Handle Jump.
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Get the input direction and handle the movement/deceleration.
    # As good practice, you should replace UI actions with custom gameplay actions.
    var input_dir = Input.get_vector("left", "right", "up", "down")
    var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
    if direction:
        velocity.x = direction.x * SPEED
        velocity.z = direction.z * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)
        velocity.z = move_toward(velocity.z, 0, SPEED)
    
    if anim_player.current_animation == "shoot":
        pass
    elif input_dir != Vector2.ZERO and is_on_floor() and weapon_sway:
        anim_player.play("move")
    else:
        anim_player.play("idle")
        
    move_and_slide()
    
@rpc("call_local")
func play_shoot_effects():
    anim_player.stop()
    anim_player.play("shoot")
    muzzle_flash.restart()
    muzzle_flash.emitting = true

@rpc("any_peer")
func receive_damage():
    health -= 1
    if health <= 0:
        health = 3
        position = Vector3.ZERO
    
    health_changed.emit(health)

@rpc("call_local")
func attempt_trigger():
    #if interactRaycast.is_colliding():
    #        var hit_object = interactRaycast.get_collider()
    #        hit_object.activate_trigger()
    interactionArea.trigger_interactable()

func _on_animation_player_animation_finished(anim_name):
    if anim_name == "shoot":
        anim_player.play("idle")
    

And there's the second half!

#

whoops, forgot the functions alright, added the functions

lavish cedar
#

The isn't active error, at what point in your game does it happen?

wheat lion
#

Strangely enough it stopped appearing. Now the last error left is the "ERR_INVALID_DATA".

It hasn't resulted in any issues connectionwise (as far as I can tell), and since we're already past "Syncing Multiplayer Interactions", I think I'll just wait to solve it later when I'm working more on the connectivity side of things. Thank you so much for the help!!!