Host Synchronization Issue

Godot Version

4.2.2

Question

Hi I’m developing a multiplayer FPS game and I’m traveling good so far but there is a small issue. The synchronization between peers work but they aren’t seeing the host’s position being updated. The host can see them just fine and the players can see each other. Hope this is a simple issue and I’m just too dumb to figure it out. Cheers.

World Code

extends Node3D

@onready var main_menu = $CanvasLayer/MainMenu
@onready var address_entry = $CanvasLayer/MainMenu/MarginContainer/VBoxContainer/AddressEntry

const Player = preload(“res://scene/world/player.tscn”)
const PORT = 25555
var enet_peer = ENetMultiplayerPeer.new()
var players = {}
var on_main_menu = false
var on_loading_screen = true
var timer = Timer.new()

func _ready():
add_child(timer)
timer.wait_time = 10.0
on_main_menu = true
if on_main_menu == true:
$Control3.hide()
$Snare_March.play()

func _unhandled_input(event):
if Input.is_action_just_pressed(“exit”):
delete_player(multiplayer.get_unique_id())
get_tree().quit()

func _on_host_button_pressed():
$Control/Control3/CanvasLayer.hide()

enet_peer.create_server(PORT)
multiplayer.multiplayer_peer = enet_peer
multiplayer.peer_connected.connect(add_player)
on_main_menu = false
$Snare_March.stop()
$Button_Click.play()

add_player(multiplayer.get_unique_id())

func _on_join_button_pressed():
$Control/Control3/CanvasLayer.hide()

enet_peer.create_client("192.168.0.146", PORT)
multiplayer.multiplayer_peer = enet_peer
multiplayer.peer_connected.connect(add_player)
on_main_menu = false
$Snare_March.stop()
$Button_Click.play()

add_player(multiplayer.get_unique_id())

func add_player(peer_id):
var player = Player.instantiate()
player.name = str(peer_id)
add_child(player)
players[player.name] = player # Store the player reference in the dictionary
print(player.name)
player.set_multiplayer_authority(peer_id)

func delete_player(peer_id):
var player = get_node(str(peer_id))
if player != null:
player.queue_free()
players.erase(str(peer_id))

Player Code

extends CharacterBody3D

@onready var camera = $Camera3D
@onready var anim_player = $AnimationPlayer
@onready var muzzel_flash = $Camera3D/Node3D/MuzzelFlash
@onready var host_button = $“…/CanvasLayer/MainMenu/MarginContainer/VBoxContainer/HostButton”
@onready var join_button = $“…/CanvasLayer/MainMenu/MarginContainer/VBoxContainer/JoinButton”
@onready var ak_shot_sound_effect = $ak_shot

const SPEED = 5.0
const SPRINT_SPEED = 7.5
const JUMP_VELOCITY = 10.0

var gravity = 30.0

var character_has_zoomed_in = false

func _enter_tree():
set_multiplayer_authority(multiplayer.get_unique_id())

func _ready():
if is_multiplayer_authority(): return

camera.current = true

func _input(event):
if not is_multiplayer_authority(): return
if event is InputEventMouseMotion:
self.rotate_y(-event.relative.x * 0.001)
camera.rotate_x(-event.relative.y * 0.001)
camera.rotation.x = clamp(camera.rotation.x, -PI/2, PI/2)

func play_shoot_effects():
if not is_multiplayer_authority(): return
anim_player.stop()
ak_shot_sound_effect.play()
anim_player.play(“shoot”)
muzzel_flash.restart()
muzzel_flash.emitting = true

func _physics_process(delta):
if not is_multiplayer_authority(): return
if not is_on_floor():
velocity.y -= gravity * delta
if character_has_zoomed_in == false:
if Input.is_action_pressed(“shoot”):
if anim_player.current_animation != “shoot” and anim_player.current_animation != “zoomed_in”:
play_shoot_effects()

if Input.is_action_pressed("zoom"):
	if character_has_zoomed_in == false:
		if anim_player.current_animation != "zoom_in": #if the player has pressed RMB and the animation has not started then zoom in
			character_has_zoomed_in = true # Set this to true here
			anim_player.stop()
			anim_player.play("zoom_in")

if Input.is_action_pressed("zoom"):
	if anim_player.current_animation != "zoom_in":
		if character_has_zoomed_in == true:
			anim_player.stop()
			anim_player.play("zoomed_in")
			$Crosshair.hide()
		
if Input.is_action_just_released("zoom"): # Check if the zoom action is released
	if character_has_zoomed_in == true:
		anim_player.stop()
		anim_player.play("zoom_out")
		character_has_zoomed_in = false # Set this to false here
		$Crosshair.show()

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

var input_dir = Input.get_vector("left", "right", "forward", "backward")
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 Input.is_action_pressed("alt"):
	Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

if Input.is_action_pressed("sprint"):
	velocity.x = direction.x * SPRINT_SPEED
	velocity.z = direction.z * SPRINT_SPEED

if anim_player.current_animation != "zoom_in" and anim_player.current_animation != "shoot" and anim_player.current_animation != "zoomed_in" and anim_player.current_animation != "zoom_out":
	if input_dir != Vector2.ZERO and is_on_floor():
		anim_player.play("move")
	else:
		anim_player.play("idle")

move_and_slide()

Do you use a multiplayer spawner?

yes but I have used @rpc to fix this but I want to find a better solution.
Here is the player code:
extends CharacterBody3D

const SPEED = 5.0
const SPRINT_SPEED = 7.5
const JUMP_VELOCITY = 10.0
const SHOT_DELAY = 0.1

var gravity = 30.0
var shot_fired = false
var character_has_zoomed_in = false
var shot_delay = 0.0

@onready var camera = $Camera3D
@onready var anim_player = $AnimationPlayer
@onready var muzzel_flash = $Camera3D/ak/MuzzelFlash
@onready var ak_shot_sound_effect = $ak_shot
@onready var ak = $Camera3D/ak

func _enter_tree():
set_multiplayer_authority(multiplayer.get_unique_id())

func _ready():
if is_multiplayer_authority(): return
camera.current = true

func _process(delta):
if shot_delay > 0:
shot_delay -= delta
if shot_delay <= 0:
shot_fired = false

func play_shoot_effects():
if not is_multiplayer_authority(): return
anim_player.stop()
ak_shot_sound_effect.play()
anim_player.play(“shoot”)
muzzel_flash.restart()
muzzel_flash.emitting = true
shot_fired = true
shot_delay = SHOT_DELAY

func play_shoot_effects_zoom():
if not is_multiplayer_authority(): return
anim_player.stop()
ak_shot_sound_effect.play()
anim_player.play(“shoot_zoomed_in”)
muzzel_flash.restart()
muzzel_flash.emitting = true
shot_fired = true
shot_delay = SHOT_DELAY

func _input(event):
if not is_multiplayer_authority(): return
if event is InputEventMouseMotion:
self.rotate_y(-event.relative.x * 0.001)
camera.rotate_x(-event.relative.y * 0.001)
camera.rotation.x = clamp(camera.rotation.x, -PI/2, PI/2)

func _physics_process(delta):
if not is_multiplayer_authority(): return

if not is_on_floor():
	velocity.y -= gravity * delta

if not character_has_zoomed_in and Input.is_action_pressed("shoot") and anim_player.current_animation in ["idle", "move"] and not shot_fired:
	play_shoot_effects()

if Input.is_action_pressed("shoot") and anim_player.current_animation == "zoomed_in" and not shot_fired:
	play_shoot_effects_zoom()

if Input.is_action_pressed("zoom"):
	if not character_has_zoomed_in and anim_player.current_animation != "zoom_in":
		character_has_zoomed_in = true
		anim_player.stop()
		anim_player.play("zoom_in")

if Input.is_action_pressed("zoom") and anim_player.current_animation != "zoom_in" and character_has_zoomed_in:
	if anim_player.current_animation != "shoot_zoomed_in":
		anim_player.stop()
		anim_player.play("zoomed_in")
		$Crosshair.hide()
		
if Input.is_action_just_released("zoom") and character_has_zoomed_in:
	anim_player.stop()
	anim_player.play("zoom_out")
	character_has_zoomed_in = false
	$Crosshair.show()

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

var input_dir = Input.get_vector("left", "right", "forward", "backward")
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 Input.is_action_pressed("alt"):
	Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

if Input.is_action_pressed("sprint"):
	velocity.x = direction.x * SPRINT_SPEED
	velocity.z = direction.z * SPRINT_SPEED

if anim_player.current_animation not in ["zoom_in", "shoot", "zoomed_in", "zoom_out"]:
	if input_dir != Vector2.ZERO and is_on_floor():
		anim_player.play("move")
	else:
		anim_player.play("idle")

move_and_slide()

if not is_multiplayer_authority(): return
$Camera3D/arms.visible = !is_multiplayer_authority()
$body.visible = !is_multiplayer_authority()

rpc_list()

func rpc_list():
rpc(“remote_set_position”, global_position)
rpc(“remote_set_rotation”, global_rotation)
rpc(“remote_set_rotation_camera”, camera.rotation)
rpc(“ak_set_position”, ak.position)
rpc(“ak_set_rotation”, ak.rotation)
rpc(“muzzel_flash_emitting”, muzzel_flash.emitting)

@rpc(“unreliable”)
func remote_set_position(new_position):
global_position = new_position

@rpc(“unreliable”)
func remote_set_rotation(new_rotation):
global_rotation = new_rotation

@rpc(“unreliable”)
func remote_set_rotation_camera(new_rotation):
camera.rotation = new_rotation

@rpc(“unreliable”)
func ak_set_position(new_position):
ak.position = new_position

@rpc(“unreliable”)
func ak_set_rotation(new_rotation):
ak.rotation = new_rotation

@rpc(“unreliable”)
func muzzel_flash_emitting(new_emitting):
muzzel_flash.emitting = new_emitting

Here is the world code:
extends Node3D

@onready var main_menu = $CanvasLayer/MainMenu
@onready var address_entry = $CanvasLayer/MainMenu/MarginContainer/VBoxContainer/AddressEntry

const Player = preload(“res://scene/world/player.tscn”)
const PORT = 25555
var enet_peer = ENetMultiplayerPeer.new()
var players = {}
var on_main_menu = false
var on_loading_screen = true
var timer = Timer.new()
var list_of_ids =

func _ready():
add_child(timer)
timer.wait_time = 10.0
on_main_menu = true
if on_main_menu == true:
$“Loading Screen”.hide()
$“Are You Sure You Want To Quit/CanvasLayer”.hide()
$Snare_March.play()

func _unhandled_input(event):
if on_main_menu == false:
if Input.is_action_just_pressed(“exit”):
$“Are You Sure You Want To Quit/CanvasLayer”.show()

func _on_yes_pressed():
delete_player(multiplayer.get_unique_id())
get_tree().quit()

func _on_no_pressed():
$“Are You Sure You Want To Quit/CanvasLayer”.hide()

func _on_host_button_pressed():
if on_main_menu == true:
$“Main Menu/Control3/CanvasLayer”.hide()

	enet_peer.create_server(PORT)
	multiplayer.multiplayer_peer = enet_peer
	multiplayer.peer_connected.connect(add_player)
	on_main_menu = false
	$Snare_March.stop()
	$Button_Click.play()
	
	add_player(multiplayer.get_unique_id())

func _on_join_button_pressed():
if on_main_menu == true:
$“Main Menu/Control3/CanvasLayer”.hide()

	enet_peer.create_client("127.0.0.1", PORT)
	multiplayer.multiplayer_peer = enet_peer
	multiplayer.peer_connected.connect(add_player)
	on_main_menu = false
	$Snare_March.stop()
	$Button_Click.play()
	
	add_player(multiplayer.get_unique_id())

func add_player(peer_id):
var player = Player.instantiate()
player.name = str(peer_id)
add_child(player)
players[player.name] = player # Store the player reference in the dictionary
player.set_multiplayer_authority(peer_id)
if peer_id not in list_of_ids:
list_of_ids.append(peer_id)
print_list()

func delete_player(peer_id):
rpc(“del_player”, peer_id)

@rpc(“any_peer”,“call_local”)
func del_player(peer_id):
get_node(str(peer_id)).queue_free()
list_of_ids.erase(peer_id)

func print_list():
print(list_of_ids)

You have already posted this code, and it’s very hard to read if it’s not formatted. Please use a code block.

```
Your Code
```

Use the back tics like this.

Please also use spaces to show indentations sometimes the leading white space doesn’t make it when copied.

Anyway since you set the player authority like this

It is not correct. Every player will set the players spawned to their authority. You only need to set one.

The most common way to handle this, You need to use the name to set authority correctly.

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

Since you set the name with the id like this the above suggestion should work.

If for whatever reason there is a error when setting authority in _entee_tree or _ready, you should try using a deffered_call("set_multiplayer_authority",name.to_int())