From 2b5935feaedaec32d552aef0c0592024e10e49fd Mon Sep 17 00:00:00 2001 From: Chris Bell Date: Thu, 19 Dec 2024 20:18:58 -0600 Subject: [PATCH] The AI made this --- assets/core/ships/ship_script.gd | 143 +++++++++++++++++++------------ 1 file changed, 86 insertions(+), 57 deletions(-) diff --git a/assets/core/ships/ship_script.gd b/assets/core/ships/ship_script.gd index fa629a2..cdd051b 100644 --- a/assets/core/ships/ship_script.gd +++ b/assets/core/ships/ship_script.gd @@ -1,6 +1,5 @@ -class_name Ship - extends RigidBody3D +class_name Ship @export var player_detection_area: Area3D @export var helm_location_marker: Marker3D @@ -26,62 +25,89 @@ var old_global_position_cache: Vector3 @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 func _ready(): network_uuid = NetworkManager.register_node(self) NetworkManager.property_update_received.connect(_on_property_update) - + #connect signals player_detection_area.body_entered.connect(_on_area_3d_body_entered) player_detection_area.body_exited.connect(_on_area_3d_body_exited) - + _add_ship_helm(ship_helm_scene) #TEMPORARY TEST - + ship_id = randi_range(1000, 9999) #assign a random id to the ship as a unique identifier GameConsole.log_debug("Ship ID: " + str(ship_id)) + # Initialize predicted values + predicted_position = global_position + predicted_rotation = Quaternion.from_euler(global_rotation) func _process(delta: float) -> void: delta_time = delta - func _physics_process(_delta) -> void: - if piloting_player != null and !piloting_player.is_network_authority: return - if ship_is_piloted: - var turn_speed = base_turn_speed / max(mass, 1) - var lift_speed = base_lift_speed / max(mass, 1) + # Predict movement only for non-authority clients + if not piloting_player or piloting_player.is_network_authority: + _predict_movement(_delta) + else: + # Apply predicted values until server correction arrives + global_position = predicted_position + global_rotation = predicted_rotation.get_euler() - 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) - - if Input.is_action_pressed("jump"): - linear_velocity.y += lift_speed - elif Input.is_action_pressed("crouch"): - linear_velocity.y -= lift_speed - - 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 - var current_acceleration = (target_velocity - linear_velocity) * acceleration - apply_central_force(current_acceleration * mass) - if linear_velocity.length() > top_speed: - linear_velocity = linear_velocity.normalized() * top_speed - - angular_velocity.y = clamp(angular_velocity.y, -max_turn_speed, max_turn_speed) + # 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) - - _send_ship_sync() - + _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) + var predicted_angular_velocity = angular_velocity + var predicted_rotation_delta = Quaternion() + predicted_rotation_delta.set_axis_angle(predicted_angular_velocity, _delta) + predicted_rotation = predicted_rotation * predicted_rotation_delta + +func _apply_local_input(_delta): + var turn_speed = base_turn_speed / max(mass, 1) + var lift_speed = base_lift_speed / max(mass, 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) + + if Input.is_action_pressed("jump"): + linear_velocity.y += lift_speed + elif Input.is_action_pressed("crouch"): + linear_velocity.y -= lift_speed + + 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 + var current_acceleration = (target_velocity - linear_velocity) * acceleration + apply_central_force(current_acceleration * mass) + if linear_velocity.length() > top_speed: + linear_velocity = linear_velocity.normalized() * top_speed + + 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: @@ -90,7 +116,6 @@ func _on_area_3d_body_entered(body: Node3D) -> void: body.call_deferred("reparent", self, true) #reparents player onto self (RigidBody3D) print("ENTERED") - func _on_area_3d_body_exited(body: Node3D) -> void: if body is Player and body.get_parent() != get_node("/root/DevLevel/"): body.ship_exited() @@ -99,48 +124,52 @@ func _on_area_3d_body_exited(body: Node3D) -> void: body.call_deferred("reparent", get_node("/root/DevLevel/"), true) #reparents player back onto world node print("EXITED") - 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_instance = helm_location_marker.get_node("ShipHelm") - 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) 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) NetworkManager.sync_property(network_uuid, "piloting_player", piloting_player) - func _send_ship_sync(): - if piloting_player != null && !piloting_player.is_network_authority: - var sync_buffer: float = 2 - if old_global_position_cache.distance_squared_to(global_position) > sync_buffer: - NetworkManager.sync_property(network_uuid, "global_position", global_position) - old_global_position_cache = global_position - - if old_global_rotation_cache.distance_squared_to(global_rotation) > sync_buffer: - NetworkManager.sync_property(network_uuid, "global_rotation", global_rotation) - old_global_rotation_cache = global_rotation - - -func _handle_ship_sync_position(pos: Vector3): - global_position = lerp(global_position, pos, 0.1 * delta_time) + if Time.get_ticks_msec() - last_sync_time > sync_interval * 1000: + last_sync_time = Time.get_ticks_msec() + 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) +func _handle_ship_sync_position(pos: Vector3): + if piloting_player and not piloting_player.is_network_authority: + # Correct prediction with server data + predicted_position = pos + linear_velocity = (pos - global_position) / delta_time func _handle_ship_sync_rotation(rot: Vector3): - global_rotation = lerp(global_rotation, rot, 0.1 * delta_time) + if piloting_player and not piloting_player.is_network_authority: + # Correct prediction with server data + predicted_rotation = Quaternion.from_euler(Vector3(rot.x, rot.y, rot.z)) + # Calculate angular velocity based on rotation change + 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() > 0.001: + angular_velocity = delta_rot.get_euler() / delta_time + + # Apply server rotation directly + global_rotation = Quaternion.from_euler(rot).get_euler()