Add direct-connect multiplayer foundation
This commit is contained in:
parent
9e9850dd20
commit
24f8263175
36 changed files with 2633 additions and 45 deletions
227
player/player.gd
227
player/player.gd
|
|
@ -105,6 +105,20 @@ var _showcase_restore_tween: Tween
|
|||
var _showcase_camera_tween: Tween
|
||||
var _showcase_camera_snapshot: ShowcaseCameraSnapshot
|
||||
var _showcase_restore_generation: int = 0
|
||||
var _network_peer_id: int = 0
|
||||
var _network_authoritative_simulation: bool = false
|
||||
var _network_interpolation_enabled: bool = false
|
||||
var _network_axis: Vector2 = Vector2.ZERO
|
||||
var _network_camera_yaw: float = 0.0
|
||||
var _network_jump_pending: bool = false
|
||||
var _network_sprint: bool = false
|
||||
var _network_sneak: bool = false
|
||||
var _network_slow_walk: bool = false
|
||||
var _last_network_input_sequence: int = 0
|
||||
var _network_target_position: Vector3
|
||||
var _network_target_velocity: Vector3
|
||||
var _network_target_visual_yaw: float = 0.0
|
||||
var _network_snapshot_ready: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -114,6 +128,9 @@ func _ready() -> void:
|
|||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if _network_interpolation_enabled:
|
||||
_update_network_interpolation(delta)
|
||||
return
|
||||
if _water_recovery_active:
|
||||
velocity = Vector3.ZERO
|
||||
return
|
||||
|
|
@ -125,34 +142,50 @@ func _physics_process(delta: float) -> void:
|
|||
else fall_gravity_multiplier
|
||||
)
|
||||
velocity.y -= _gravity * gravity_multiplier * delta
|
||||
elif (
|
||||
local_control_enabled
|
||||
and _movement_enabled
|
||||
and Input.is_action_just_pressed("jump")
|
||||
elif _movement_enabled and (
|
||||
(
|
||||
local_control_enabled
|
||||
and Input.is_action_just_pressed("jump")
|
||||
)
|
||||
or (
|
||||
_network_authoritative_simulation
|
||||
and _network_jump_pending
|
||||
)
|
||||
):
|
||||
velocity.y = jump_velocity
|
||||
_network_jump_pending = false
|
||||
|
||||
if not local_control_enabled or not _movement_enabled:
|
||||
if not _movement_enabled:
|
||||
velocity.x = 0.0
|
||||
velocity.z = 0.0
|
||||
move_and_slide()
|
||||
return
|
||||
|
||||
var input_vector: Vector2 = Input.get_vector(
|
||||
"move_left",
|
||||
"move_right",
|
||||
"move_forward",
|
||||
"move_backward"
|
||||
)
|
||||
var camera_basis: Basis = _camera_yaw.global_basis
|
||||
var input_vector: Vector2
|
||||
var camera_basis: Basis
|
||||
if local_control_enabled:
|
||||
input_vector = Input.get_vector(
|
||||
"move_left",
|
||||
"move_right",
|
||||
"move_forward",
|
||||
"move_backward"
|
||||
)
|
||||
camera_basis = _camera_yaw.global_basis
|
||||
elif _network_authoritative_simulation:
|
||||
input_vector = _network_axis
|
||||
camera_basis = Basis(Vector3.UP, _network_camera_yaw)
|
||||
else:
|
||||
velocity.x = 0.0
|
||||
velocity.z = 0.0
|
||||
return
|
||||
var move_direction: Vector3 = camera_basis.x * input_vector.x + camera_basis.z * input_vector.y
|
||||
move_direction.y = 0.0
|
||||
var input_strength: float = minf(input_vector.length(), 1.0)
|
||||
move_direction = move_direction.normalized()
|
||||
|
||||
var speed: float = (
|
||||
_get_current_speed() * item_effects.get_movement_multiplier()
|
||||
)
|
||||
var speed: float = _get_network_aware_speed()
|
||||
if item_effects != null:
|
||||
speed *= item_effects.get_movement_multiplier()
|
||||
velocity.x = move_direction.x * speed * input_strength
|
||||
velocity.z = move_direction.z * speed * input_strength
|
||||
|
||||
|
|
@ -243,6 +276,18 @@ func _get_current_speed() -> float:
|
|||
return walk_speed
|
||||
|
||||
|
||||
func _get_network_aware_speed() -> float:
|
||||
if local_control_enabled:
|
||||
return _get_current_speed()
|
||||
if _network_sneak:
|
||||
return sneak_speed
|
||||
if _network_slow_walk:
|
||||
return slow_walk_speed
|
||||
if _network_sprint:
|
||||
return sprint_speed
|
||||
return walk_speed
|
||||
|
||||
|
||||
func _rotate_camera(delta_rotation: Vector2) -> void:
|
||||
_camera_yaw.rotation.y -= delta_rotation.x
|
||||
var vertical_direction: float = -1.0 if invert_camera_y else 1.0
|
||||
|
|
@ -265,6 +310,158 @@ func set_local_control(enabled: bool) -> void:
|
|||
_camera_dragging = false
|
||||
|
||||
|
||||
func set_network_peer_id(peer_id: int) -> void:
|
||||
_network_peer_id = peer_id
|
||||
|
||||
|
||||
func get_network_peer_id() -> int:
|
||||
return _network_peer_id
|
||||
|
||||
|
||||
func configure_network_remote(authoritative_simulation: bool) -> void:
|
||||
set_local_control(false)
|
||||
_network_authoritative_simulation = authoritative_simulation
|
||||
_network_interpolation_enabled = not authoritative_simulation
|
||||
_network_snapshot_ready = false
|
||||
_camera.current = false
|
||||
|
||||
|
||||
func capture_network_input(sequence: int) -> Dictionary:
|
||||
var axis: Vector2 = Input.get_vector(
|
||||
"move_left",
|
||||
"move_right",
|
||||
"move_forward",
|
||||
"move_backward"
|
||||
)
|
||||
return {
|
||||
"sequence": sequence,
|
||||
"axis": [axis.x, axis.y],
|
||||
"camera_yaw": _camera_yaw.global_rotation.y,
|
||||
"jump": Input.is_action_just_pressed("jump"),
|
||||
"sprint": Input.is_action_pressed("sprint"),
|
||||
"sneak": Input.is_action_pressed("sneak"),
|
||||
"slow_walk": Input.is_action_pressed("slow_walk"),
|
||||
}
|
||||
|
||||
|
||||
func apply_authoritative_network_input(data: Dictionary) -> void:
|
||||
var sequence: int = int(data.get("sequence", 0))
|
||||
if sequence <= _last_network_input_sequence:
|
||||
return
|
||||
var axis: Array = data.get("axis", [])
|
||||
if axis.size() != 2:
|
||||
return
|
||||
_last_network_input_sequence = sequence
|
||||
_network_axis = Vector2(float(axis[0]), float(axis[1])).limit_length(1.0)
|
||||
_network_camera_yaw = float(data.get("camera_yaw", 0.0))
|
||||
_network_jump_pending = bool(data.get("jump", false))
|
||||
_network_sprint = bool(data.get("sprint", false))
|
||||
_network_sneak = bool(data.get("sneak", false))
|
||||
_network_slow_walk = bool(data.get("slow_walk", false))
|
||||
|
||||
|
||||
func make_network_snapshot(peer_id: int) -> Dictionary:
|
||||
return {
|
||||
"peer_id": peer_id,
|
||||
"acknowledged_input": _last_network_input_sequence,
|
||||
"position": [global_position.x, global_position.y, global_position.z],
|
||||
"velocity": [velocity.x, velocity.y, velocity.z],
|
||||
"visual_yaw": _visuals.rotation.y,
|
||||
"grounded": is_on_floor(),
|
||||
}
|
||||
|
||||
|
||||
func push_network_snapshot(snapshot: Dictionary) -> void:
|
||||
var parsed: Dictionary = _parse_network_snapshot(snapshot)
|
||||
if parsed.is_empty():
|
||||
return
|
||||
_network_target_position = parsed["position"]
|
||||
_network_target_velocity = parsed["velocity"]
|
||||
_network_target_visual_yaw = parsed["visual_yaw"]
|
||||
if not _network_snapshot_ready:
|
||||
global_position = _network_target_position
|
||||
velocity = _network_target_velocity
|
||||
_visuals.rotation.y = _network_target_visual_yaw
|
||||
_network_snapshot_ready = true
|
||||
|
||||
|
||||
func apply_local_prediction_correction(snapshot: Dictionary) -> void:
|
||||
var parsed: Dictionary = _parse_network_snapshot(snapshot)
|
||||
if parsed.is_empty():
|
||||
return
|
||||
var authoritative_position: Vector3 = parsed["position"]
|
||||
var error_distance: float = global_position.distance_to(
|
||||
authoritative_position
|
||||
)
|
||||
if error_distance > 2.0:
|
||||
global_position = authoritative_position
|
||||
elif error_distance > 0.05:
|
||||
global_position = global_position.lerp(authoritative_position, 0.18)
|
||||
|
||||
|
||||
func apply_network_teleport(snapshot: Dictionary) -> void:
|
||||
var parsed: Dictionary = _parse_network_snapshot(snapshot)
|
||||
if parsed.is_empty():
|
||||
return
|
||||
global_position = parsed["position"]
|
||||
velocity = parsed["velocity"]
|
||||
_visuals.rotation.y = parsed["visual_yaw"]
|
||||
_network_target_position = global_position
|
||||
_network_target_velocity = velocity
|
||||
_network_target_visual_yaw = _visuals.rotation.y
|
||||
_network_snapshot_ready = true
|
||||
|
||||
|
||||
func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
||||
var position: Variant = snapshot.get("position")
|
||||
var network_velocity: Variant = snapshot.get("velocity")
|
||||
if (
|
||||
typeof(position) != TYPE_ARRAY
|
||||
or typeof(network_velocity) != TYPE_ARRAY
|
||||
or position.size() != 3
|
||||
or network_velocity.size() != 3
|
||||
):
|
||||
return {}
|
||||
var parsed_position := Vector3(
|
||||
float(position[0]),
|
||||
float(position[1]),
|
||||
float(position[2])
|
||||
)
|
||||
var parsed_velocity := Vector3(
|
||||
float(network_velocity[0]),
|
||||
float(network_velocity[1]),
|
||||
float(network_velocity[2])
|
||||
)
|
||||
var visual_yaw: float = float(snapshot.get("visual_yaw", 0.0))
|
||||
if (
|
||||
not parsed_position.is_finite()
|
||||
or not parsed_velocity.is_finite()
|
||||
or not is_finite(visual_yaw)
|
||||
):
|
||||
return {}
|
||||
return {
|
||||
"position": parsed_position,
|
||||
"velocity": parsed_velocity,
|
||||
"visual_yaw": visual_yaw,
|
||||
}
|
||||
|
||||
|
||||
func _update_network_interpolation(delta: float) -> void:
|
||||
if not _network_snapshot_ready:
|
||||
return
|
||||
var position_weight: float = 1.0 - exp(-12.0 * delta)
|
||||
global_position = global_position.lerp(
|
||||
_network_target_position,
|
||||
position_weight
|
||||
)
|
||||
velocity = _network_target_velocity
|
||||
_visuals.rotation.y = lerp_angle(
|
||||
_visuals.rotation.y,
|
||||
_network_target_visual_yaw,
|
||||
1.0 - exp(-14.0 * delta)
|
||||
)
|
||||
|
||||
|
||||
func is_local_control_enabled() -> bool:
|
||||
return local_control_enabled
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue