diff --git a/assets/core/interactables/ship-helm/ship_helm.gd b/assets/core/interactables/ship-helm/ship_helm.gd index cf8a59a..0f3ba85 100644 --- a/assets/core/interactables/ship-helm/ship_helm.gd +++ b/assets/core/interactables/ship-helm/ship_helm.gd @@ -1,34 +1,20 @@ class_name ShipHelm - extends Interactable var parent_ship: Ship -var uuid: String = "" - - func _ready(): - uuid = NetworkManager.register_node(self) - NetworkManager.property_update_received.connect(_on_property_update) parent_ship = get_parent().get_parent() #sets the parent ship to the ship that the helm is placed on - NetworkManager.sync_property(uuid, "parent_ship", parent_ship) func interact(): if player_reference.is_network_authority: if !parent_ship.ship_is_piloted: player_reference.set_is_piloting(true) - parent_ship.ship_is_piloted = true + parent_ship.set_piloting_player(player_reference) elif parent_ship.ship_is_piloted: player_reference.set_is_piloting(false) - parent_ship.ship_is_piloted = false + parent_ship.remove_piloting_player() parent_ship._sync_piloting_state() - - -func _on_property_update(uuid: String, property_name: String, value: Variant): - if NetworkManager.node_map.has(uuid): - var node = NetworkManager.node_map[uuid] - node.set(property_name, value) - else: - printerr("Received property update but node_id is wrong? Expected " + str(uuid) + " but got " + str(uuid)) + \ No newline at end of file diff --git a/assets/core/ships/ship_script.gd b/assets/core/ships/ship_script.gd index f3f316f..d597a96 100644 --- a/assets/core/ships/ship_script.gd +++ b/assets/core/ships/ship_script.gd @@ -1,223 +1,105 @@ -extends RigidBody3D class_name Ship +extends RigidBody3D + @export var player_detection_area: Area3D @export var helm_location_marker: Marker3D -var delta_time: float = 0.0 - -var ship_helm_scene: PackedScene = load("res://assets/core/interactables/ship-helm/ship-helm.tscn") - -var ship_helm: ShipHelm = null var piloting_player: Player = null -#var ship_id: int = random_int() # Generate a random ship ID var ship_is_piloted: bool = false -var current_level: Node = null -var network_uuid: String = "" -var old_global_rotation_cache: Vector3 -var old_global_position_cache: Vector3 - -var rotation_correction: Vector3 -var position_correction: Vector3 - -@export_range(0.01, 1.0, 0.01) var base_turn_speed: float = 0.35 +@export var base_turn_speed: float = 0.35 @export var max_turn_speed: float = 0.5 -@export_range(0.01, 10.0, 0.01) var base_lift_speed: float = 2.0 +@export var base_lift_speed: float = 2.0 @export var top_speed: float = 5.0 @export var move_speed: float = 1.0 @export var acceleration: float = 0.1 -# Network Synchronization Variables -var last_sync_time: float = 0.0 -var sync_interval: float = 0.1 # Sync every 0.1 seconds - -var predicted_position: Vector3 -var predicted_rotation: Quaternion +# Networking +var network_uuid: String = "" +var target_position: Vector3 = Vector3.ZERO +var target_rotation: Quaternion = Quaternion() +var previous_position: Vector3 +var previous_rotation: Quaternion func _ready(): - # Register the ship with the NetworkManager for P2P communication network_uuid = NetworkManager.register_node(self) - NetworkManager.property_update_received.connect(_on_property_update) + target_position = global_position + target_rotation = global_transform.basis.get_rotation_quaternion() + previous_position = global_position + previous_rotation = global_transform.basis.get_rotation_quaternion() - # Connect signals for player interaction - player_detection_area.body_entered.connect(_on_area_3d_body_entered) - player_detection_area.body_exited.connect(_on_area_3d_body_exited) + NetworkManager.property_update_received.connect(_on_property_update_received) - # Spawn the ship helm visually (optional based on your design) - _add_ship_helm(ship_helm_scene) - - # Initialize predicted values - predicted_position = global_position - predicted_rotation = Quaternion.from_euler(global_rotation).normalized() - -func _process(delta: float) -> void: - delta_time = delta - -func _physics_process(_delta): - # Predict movement only for non-authority clients - if not piloting_player or piloting_player.is_network_authority: - _predict_movement(_delta) +func _process(delta: float): + if piloting_player and piloting_player.is_network_authority: + handle_input(delta) + sync_ship_state() else: - # Apply predicted values until peer correction arrives - global_position = predicted_position - global_rotation = predicted_rotation.get_euler() + interpolate_position_and_rotation(delta) - # Apply actual input if it's the authority client - if piloting_player != null and piloting_player.is_network_authority: - _apply_local_input(_delta) - - # Self level slowly if host - global_rotation.x = lerpf(global_rotation.x, 0, 0.1) - global_rotation.z = lerpf(global_rotation.z, 0, 0.1) - - # Apply corrections if available - if position_correction != Vector3.ZERO: - _handle_position_correction(position_correction) - position_correction = Vector3.ZERO - - if rotation_correction != Vector3.ZERO: - _handle_rotation_correction(rotation_correction) - rotation_correction = Vector3.ZERO - - # Send network updates periodically - _send_ship_sync() - -func _predict_movement(_delta): - # Simple linear prediction - var predicted_velocity = linear_velocity - predicted_position += predicted_velocity * _delta - - # Basic rotation prediction (can be improved) - if angular_velocity.length() > 0: - var predicted_angular_velocity = angular_velocity.normalized() - var predicted_rotation_delta = Quaternion(predicted_angular_velocity, _delta) - predicted_rotation = predicted_rotation * predicted_rotation_delta - -func _apply_local_input(_delta): - if piloting_player == null or not piloting_player.is_network_authority or not piloting_player.is_piloting: - return - - var turn_speed = base_turn_speed / max(mass, 1) - var lift_speed = base_lift_speed / max(mass, 1) +func handle_input(delta: float): + var input_vector = Vector3.ZERO + if Input.is_action_pressed("move_forward"): + input_vector.z -= 1 + if Input.is_action_pressed("move_backward"): + input_vector.z += 1 if Input.is_action_pressed("move_left"): - angular_velocity.y += turn_speed - elif Input.is_action_pressed("move_right"): - angular_velocity.y -= turn_speed - else: - global_rotation.z = lerpf(global_rotation.z, 0, 0.8) + input_vector.x -= 1 + if Input.is_action_pressed("move_right"): + input_vector.x += 1 + if Input.is_action_pressed("move_up"): + input_vector.y += 1 + if Input.is_action_pressed("move_down"): + input_vector.y -= 1 - if Input.is_action_pressed("jump"): - linear_velocity.y += lift_speed - elif Input.is_action_pressed("crouch"): - linear_velocity.y -= lift_speed + if input_vector.length() > 0: + input_vector = input_vector.normalized() * move_speed + apply_force(input_vector) - var target_velocity = Vector3.ZERO - if Input.is_action_pressed("move_forwards"): - target_velocity = -transform.basis.z * top_speed - elif Input.is_action_pressed("move_backwards"): - target_velocity = transform.basis.z * top_speed + # Rotation handling + var yaw = Input.get_action_strength("turn_right") - Input.get_action_strength("turn_left") + var pitch = Input.get_action_strength("turn_up") - Input.get_action_strength("turn_down") - var current_acceleration = (target_velocity - linear_velocity) * acceleration - apply_central_force(current_acceleration * mass) + if yaw != 0 or pitch != 0: + apply_torque(Vector3(pitch, yaw, 0) * base_turn_speed) - # Clamp velocity to prevent excessive speed - if linear_velocity.length() > top_speed: - linear_velocity = linear_velocity.normalized() * top_speed - - # Clamp angular velocity to prevent excessive turning - angular_velocity.y = clamp(angular_velocity.y, -max_turn_speed, max_turn_speed) - -func _on_area_3d_body_entered(body: Node3D) -> void: - if body is Player and body.get_parent() != self: - body.ship_entered(self) - piloting_player = body - body.call_deferred("reparent", self, true) # Reparents player onto the ship - ship_is_piloted = true - _sync_piloting_state() # Update piloting state for other clients - -func _on_area_3d_body_exited(body: Node3D) -> void: - if body is Player and body.get_parent() != get_node("/root/DevLevel/"): - body.ship_exited() - ship_is_piloted = false - piloting_player = null - body.call_deferred("reparent", get_node("/root/DevLevel/"), true) # Reparents player back to the world - _sync_piloting_state() # Update piloting state for other clients - -func _add_ship_helm(_ship_helm_scene: PackedScene): - var ship_helm_instance = _ship_helm_scene.instantiate() - helm_location_marker.add_child(ship_helm_instance) - ship_helm = helm_location_marker.get_node("ShipHelm") # Assuming "ShipHelm" is the node name - -func _on_property_update(uuid: String, property_name: String, value: Variant): - if NetworkManager.node_map.has(uuid): - var node = NetworkManager.node_map[uuid] - - if property_name == "global_position": - _handle_ship_sync_position(value) - elif property_name == "global_rotation": - _handle_ship_sync_rotation(value) - elif property_name == "ship_is_piloted": - ship_is_piloted = value - elif property_name == "piloting_player": - if value != "": - # Find the Player object based on the network_uuid - for child in get_parent().get_children(): - if child is Player and child.network_uuid == value: - piloting_player = child - break - else: - piloting_player = null - else: - node.set(property_name, value) - else: - printerr("Received property update but node_id is wrong? Expected " + str(uuid) + " but got " + str(uuid)) - -func _sync_piloting_state(): - NetworkManager.sync_property(network_uuid, "ship_is_piloted", ship_is_piloted) - if piloting_player != null: - NetworkManager.sync_property(network_uuid, "piloting_player", piloting_player.network_uuid) - else: - NetworkManager.sync_property(network_uuid, "piloting_player", "") - -func _send_ship_sync(): - if Time.get_ticks_msec() - last_sync_time > sync_interval * 1000: - last_sync_time = Time.get_ticks_msec() +func sync_ship_state(): + if global_position != previous_position: NetworkManager.sync_property(network_uuid, "global_position", global_position) - NetworkManager.sync_property(network_uuid, "global_rotation", global_rotation) - NetworkManager.sync_property(network_uuid, "linear_velocity", linear_velocity) - NetworkManager.sync_property(network_uuid, "angular_velocity", angular_velocity) + previous_position = global_position -func _handle_ship_sync_position(pos: Vector3): - if piloting_player and not piloting_player.is_network_authority: - # Correct prediction with server data - var correction_threshold = 0.5 # Adjust based on your desired tolerance - if (pos - global_position).length() > correction_threshold: - position_correction = pos + var current_rotation = global_transform.basis.get_rotation_quaternion() + if current_rotation != previous_rotation: + NetworkManager.sync_property(network_uuid, "global_rotation", current_rotation) + previous_rotation = current_rotation -func _handle_ship_sync_rotation(rot: Vector3): - if piloting_player and not piloting_player.is_network_authority: - var correction_threshold = 0.1 # Adjust based on your desired tolerance - var received_rotation = Quaternion.from_euler(Vector3(rot.x, rot.y, rot.z)) - var delta_rot = received_rotation * global_rotation.inverse() - if delta_rot.length() > correction_threshold: - rotation_correction = rot +func interpolate_position_and_rotation(delta: float): + global_position = lerp(global_position, target_position, acceleration * delta) + var current_rotation = global_transform.basis.get_rotation_quaternion() + var interpolated_rotation = current_rotation.slerp(target_rotation, acceleration * delta) + global_transform.basis = Basis(interpolated_rotation) - # Apply server rotation directly - global_rotation = Quaternion.from_euler(rot).get_euler() +func _on_property_update_received(node_id: String, property_name: String, value: Variant): + if node_id == network_uuid: + match property_name: + "global_position": + target_position = value + "global_rotation": + target_rotation = value -func _handle_position_correction(corrected_position: Vector3): - if piloting_player and not piloting_player.is_network_authority: - predicted_position = corrected_position - linear_velocity = (corrected_position - global_position) / delta_time +func set_piloting_player(player: Player): + piloting_player = player + ship_is_piloted = piloting_player != null + if piloting_player: + print("Player", piloting_player.username, "is now piloting the ship.") + else: + print("The ship is no longer piloted.") -func _handle_rotation_correction(corrected_rotation: Vector3): - if piloting_player and not piloting_player.is_network_authority: - var received_rotation = Quaternion.from_euler(corrected_rotation) - var delta_rot = received_rotation * global_rotation.inverse() - predicted_rotation = received_rotation - angular_velocity = Quaternion(delta_rot).get_euler() / delta_time - - # Apply server rotation directly - global_rotation = Quaternion.from_euler(corrected_rotation).get_euler() + + +func remove_piloting_player(): + piloting_player = null + ship_is_piloted = false + print("The ship is no longer piloted.") \ No newline at end of file