Reputation: 361
Explanation: I have been attempting to make an multiplayer fps game and I am currently trying to make a spawn system, for some reason the replicated/client side of players never follow the position I want, they always go to the world position which is a vector3.Zero, I have been trying everything and I just cant get it to work correctly, and google searching I found one case where someone has the same issue as me but they didn't have any solution.
Network script (is a global script):
extends Node
var server : ENetMultiplayerPeer = null
var client : ENetMultiplayerPeer = null
var port : int = 9898
var ip_address : String = "localhost"
var max_clients : int = 20
var unique_identifier : int = -1
var game_manager : Node = null
var players : Dictionary = {}
func _ready():
setup_network()
func setup_network() -> void:
multiplayer.peer_connected.connect(peer_connected)
multiplayer.peer_disconnected.connect(peer_disconnected)
multiplayer.connected_to_server.connect(connected_to_server)
multiplayer.connection_failed.connect(connection_failed)
func host_server() -> void:
server = ENetMultiplayerPeer.new()
var error = server.create_server(port,max_clients)
if error != OK:
print("Failed to create server. Error: " + error)
return
server.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)
multiplayer.multiplayer_peer = server
unique_identifier = server.get_unique_id()
send_player_info("Host",unique_identifier)
game_manager.create_player(unique_identifier)
func join_server() -> void:
client = ENetMultiplayerPeer.new()
client.create_client(ip_address,port)
client.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)
multiplayer.multiplayer_peer = client
unique_identifier = client.get_unique_id()
func peer_connected(identifier : int) -> void:
print("player has connected, ID: " + str(identifier))
if identifier != 1:
game_manager.create_player(identifier)
func peer_disconnected(identifier : int) -> void:
print("player has disconnected, ID: " + str(identifier))
var player = game_manager.get_node_or_null(str(identifier))
if player:
player.queue_free()
func connected_to_server() -> void:
print("Connected to the server")
send_player_info.rpc_id(1,"None",multiplayer.get_unique_id())
@rpc("any_peer")
func send_player_info(username : String, identifier : int) -> void:
if not players.has(identifier):
players[identifier] = {
"identifier" : identifier,
"username" : username
}
if multiplayer.is_server():
for index in players:
send_player_info.rpc(str(players[index]),index)
func connection_failed() -> void:
print("Connection failed")
GameZone script(it simply connects to the functions in the network script and also spawns the player at a specific node position):
class_name GameZone extends Node
@export_subgroup("Game Exports")
@export var menu : Control
@export var spawn_points : Node3D
const TestDummyPlayer : PackedScene = preload("res://Game/Objects/TestDummyGame/TestDummyPlayer/TestDummyPlayer.tscn")
var index : int = 0
func _ready():
Network.game_manager = self
func _on_single_player_pressed():
Network.host_server()
menu.hide()
func _on_host_pressed():
Network.host_server()
menu.hide()
func _on_join_pressed():
Network.join_server()
menu.hide()
func _on_exit_pressed():
get_tree().quit()
func _on_line_edit_text_changed(ip):
Network.ip_address = ip
func create_player(identifier : int) -> void:
if not multiplayer.is_server(): return
var instance = TestDummyPlayer.instantiate()
instance.name = str(identifier)
add_child(instance)
instance.global_position = spawn_points.global_position
The player scene just in case something is wrong with it.
extends CharacterBody3D
@export var synchronizer : MultiplayerSynchronizer
@export var camera : Camera3D
@export var horizontal_n : Node3D
@export var vertical_n : Node3D
@export var sensitivity : float = 0.001
var spawn_point : Vector3
var mouse_motion : Vector2 = Vector2.ZERO
const SPEED = 7.0
const JUMP_VELOCITY = 4.5
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
func _ready():
if not is_multiplayer_authority(): return
camera.current = true
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _enter_tree():
set_multiplayer_authority(str(name).to_int())
synchronizer.set_multiplayer_authority(str(name).to_int())
func _unhandled_input(event):
if not is_multiplayer_authority(): return
if event is InputEventMouseMotion && Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
mouse_motion = -event.relative * sensitivity
rotate_y(mouse_motion.x)
horizontal_n.rotate_x(mouse_motion.y)
horizontal_n.rotation.x = clamp(horizontal_n.rotation.x,-PI / 2, PI / 2)
func _physics_process(delta):
if not is_multiplayer_authority(): return
if Input.is_action_just_pressed("ui_cancel"):
get_tree().quit()
# Add the gravity.
if not is_on_floor():
velocity.y -= gravity * delta
# Handle jump.
if Input.is_action_just_pressed("Jump") 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", "Forward", "Backward")
var direction = (global_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)
move_and_slide()
Upvotes: 1
Views: 640
Reputation: 131
This is an older post so you may have already solved it, but thought I'd provide an answer for anyone else who sees this.
It appears that you have conflicting authority checks when a peer joins the game.
In Network's peer_connected method, you have:
func peer_connected(identifier : int) -> void:
print("player has connected, ID: " + str(identifier))
if identifier != 1:
game_manager.create_player(identifier)
Meaning that when a peer connects, all non-server clients will call create_player.
Then in GameZone's create_player method, you have:
func create_player(identifier : int) -> void:
if not multiplayer.is_server():
return
var instance = TestDummyPlayer.instantiate()
instance.name = str(identifier)
add_child(instance)
instance.global_position = spawn_points.global_position
This logic will only execute if it is the server (identifier == 1) that called this method.
This means that due to the two contradictory statements, the logic after create_player's authority check will never be run, meaning that peers never actually get spawned. In Godot, if there is no camera available, which occurs when the clients don't get a player spawned for them, a camera is spawned at the origin, which explains what you were experiencing.
To solve this, I would change peer_connected's authority check to:
if identifier == 1:
This way, the logic for spawning players will only be executed on the server, and this should result in the clients being properly spawned!
Upvotes: 0