controller cleanup

This commit is contained in:
anyreso 2026-02-22 02:13:43 -05:00
parent dba1bd1b6b
commit f2a761c277
13 changed files with 1730 additions and 227 deletions

View file

@ -19,6 +19,8 @@ dest_files=["res://.godot/imported/Particle01.png-91f92696ba4d647b684a91370e6d49
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -26,6 +28,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -19,6 +19,8 @@ dest_files=["res://.godot/imported/smoke_01.png-37c016a5a51c2cceaf682437fe75284f
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -26,6 +28,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -19,6 +19,8 @@ dest_files=["res://.godot/imported/smoke_02.png-60fd959f44b7825f3153061fdb667fe7
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -26,6 +28,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/smoke_05.png-2f5c9b30713a43c1f15c13e2ffc2abef
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -25,6 +27,10 @@ mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/smoke_06.png-a3676bce06542e67baa5c4b1c38f48cd
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -25,6 +27,10 @@ mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,8 @@ dest_files=["res://.godot/imported/vanguard_0.png-7e4d2faeb963c948822713a4215f97
compress/mode=2
compress/high_quality=true
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -27,6 +29,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -20,6 +20,8 @@ dest_files=["res://.godot/imported/vanguard_1.png-bd95dbe9f4f4b9a674d90ae4deb4a8
compress/mode=2
compress/high_quality=true
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=1
compress/channel_pack=0
@ -27,6 +29,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=1
roughness/src_normal="res://entities/player/assets/vanguard_1.png"
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -20,6 +20,8 @@ dest_files=["res://.godot/imported/vanguard_2.png-369246b9d40329f77c1e8edd517f47
compress/mode=2
compress/high_quality=true
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=1
compress/channel_pack=0
@ -27,6 +29,10 @@ mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=1
roughness/src_normal="res://entities/player/assets/vanguard_2.png"
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

Binary file not shown.

Binary file not shown.

View file

@ -85,11 +85,10 @@ var control_states:Queue
@rpc("any_peer", "call_local", "reliable")
func req_loadout(idx:int = 0) -> void:
prints("req_loadout", multiplayer.get_remote_sender_id(), multiplayer.get_unique_id(), idx)
inventory.clear()
if is_multiplayer_authority():
# spawn new weapons
prints("req_loadout", self, idx)
pass
func _ready() -> void:
input.set_multiplayer_authority(peer_id)
@ -136,13 +135,9 @@ func _physics_process(_delta:float) -> void:
if not is_alive():
return
func apply_inputs(sample:Variant) -> void:
func apply_inputs(sample:Variant, delta:float) -> void:
if not sample: return
#if OS.is_debug_build():
#prints("%s:" % multiplayer.get_unique_id(), "apply Player(%s) input" % peer_id, sample)
var local_direction:Vector3 = pivot.global_transform.basis * sample.direction
# handle jetpack
if sample.jetting and energy.value > 0 and not jetpack.stuttering:
apply_force(mass * (Vector3.UP * (gravity + jetpack.vertical_acceleration) + local_direction * jetpack.horizontal_acceleration))
@ -165,11 +160,14 @@ func apply_inputs(sample:Variant) -> void:
if slope_angle <= max_floor_angle:
# retrieve normalized projection of local direction on tangent plane to normal
var tangential_direction := (local_direction - normal * local_direction.dot(normal)).normalized()
var target_velocity := tangential_direction * ground_speed
var target_force:Vector3 = mass * (target_velocity - linear_velocity) / get_physics_process_delta_time()
# @TODO: smooth acceleration
var factor := travel_acceleration_curve.sample(1.)
apply_force(target_force * factor)
var target_velocity := (tangential_direction * ground_speed) - linear_velocity
# acceleration limiter
var accel_time := .1
var max_change := (ground_speed / accel_time) * delta
if target_velocity.length() > max_change:
target_velocity = target_velocity.normalized() * max_change
apply_central_force(mass * target_velocity / delta)
if _jumping:
apply_central_impulse(basis.y * mass * sqrt(2 * gravity * jump_height))
_jumping = false
@ -187,12 +185,10 @@ func new_state(control_state:Dictionary) -> void:
var back:Dictionary = control_states.back()
# drop late control states
if control_state.id < back.id:
prints("%s: new state (dropped)" % multiplayer.get_unique_id(), control_state, back, peer_id, self)
return
prints("%s: new state" % multiplayer.get_unique_id(), control_state, peer_id, self)
control_states.enqueue(control_state)
func replay_inputs(from:int) -> void:
func replay_inputs(from:int, delta:float) -> void:
# reset local_predictions since this node needs to resync, past predictions are wrong
local_predictions = Queue.new()
# reapply unacknowledged inputs if any
@ -200,17 +196,14 @@ func replay_inputs(from:int) -> void:
for i in range(input.history.size()):
var sample:Dictionary = input.history.dequeue()
if sample.id > from:
prints("replaying from", from, sample)
input.history.enqueue(sample)
apply_inputs(sample)
apply_inputs(sample, delta)
var state := PhysicsServer3D.body_get_direct_state(get_rid())
state.integrate_forces()
# regenerate predictions
local_predictions.enqueue(get_state(sample.id))
prints("local state is now", local_predictions.back())
func reconcile(prediction:Dictionary, control:Dictionary) -> void:
prints("reconcile", prediction, control)
func reconcile(prediction:Dictionary, control:Dictionary, delta:float) -> void:
var sigma:float = .05
var resync := [
(prediction.state[0] - control.state[0]).length() > sigma,
@ -226,8 +219,7 @@ func reconcile(prediction:Dictionary, control:Dictionary) -> void:
pivot.global_rotation.y = control.state[2].y # same as spring arm
if resync.max():
prints("resync", resync)
replay_inputs(control.id)
replay_inputs(control.id, delta)
func get_state(id:int) -> Dictionary:
return {
@ -241,15 +233,14 @@ var last_control := 0
func _integrate_forces(state:PhysicsDirectBodyState3D) -> void:
if not is_alive():
return
#prints("%s:"%multiplayer.get_unique_id(), "tick", Engine.get_physics_frames(), "Player(%s)" % peer_id)
if is_pawn():
# local prediction for pawns
var sample:Dictionary = input.sample()
if multiplayer.is_server():
apply_inputs(sample)
apply_inputs(sample, state.step)
else:
input.history.enqueue(sample)
apply_inputs(sample)
apply_inputs(sample, state.step)
local_predictions.enqueue(get_state(sample.id))
if not control_states.is_empty():
var prediction:Dictionary = local_predictions.front()
@ -261,7 +252,7 @@ func _integrate_forces(state:PhysicsDirectBodyState3D) -> void:
prediction = local_predictions.dequeue()
if prediction.id == control.id:
prints("%s:" % multiplayer.get_unique_id(), "B", prediction.id, control.id)
reconcile(prediction, control)
reconcile(prediction, control, state.step)
else:
prints("%s:" % multiplayer.get_unique_id(), "B no prediction / control match, wait for next control state")
else:
@ -270,33 +261,11 @@ func _integrate_forces(state:PhysicsDirectBodyState3D) -> void:
# make sure synchronized inputs are processed once
if sample.id != last_sent_state:
last_sent_state = sample.id
apply_inputs(sample)
apply_inputs(sample, state.step)
spring_arm.rotation.x = input.rotation.x
pivot.rotation.y = input.rotation.y
new_state.rpc(get_state(sample.id))
#if not (local_predictions.is_empty() or control_states.is_empty()):
#var prediction:Dictionary = local_predictions.front()
#var control:Dictionary = control_states.front()
#prints("A", prediction.id, control.id)
## dequeue predictions until we match most fresh control state
#while prediction.id != control.id:
#if local_predictions.is_empty():
#break
#prediction = local_predictions.dequeue()
#if prediction.id == control.id:
#reconcile(prediction, control)
#prints("B", prediction.id, control.id)
#else:
#prints("B no prediction / control match, wait for next control state")
#else:
#if multiplayer.is_server():
#var sample:Dictionary = input.sample()
#apply_inputs(sample)
#new_state.rpc(get_state(sample.id))
func apply_state(control:Dictionary, do_rotate:bool = false) -> void:
global_position = control.state[0]
# apply central force to reach control state velocity
@ -304,7 +273,6 @@ func apply_state(control:Dictionary, do_rotate:bool = false) -> void:
if do_rotate:
spring_arm.global_rotation.x = control.state[2].x
pivot.global_rotation.y = control.state[2].y # same as spring arm
prints("apply_state", global_position, control.state[0])
func _unhandled_input(event: InputEvent) -> void:
if is_pawn() and event.is_action("pov") and event.pressed and not event.echo:
@ -324,11 +292,11 @@ func _unhandled_input(event: InputEvent) -> void:
func _animate_third_person() -> void:
if not is_alive():
mesh.animation_tree.set("parameters/transition/transition_request", &"dead")
mesh.animation_tree.set("parameters/transition/transition_request", "dead")
return
if is_on_floor():
#mesh.animation_tree.set("parameters/transition/transition_request", &"grounded")
mesh.animation_tree.set("parameters/transition/transition_request", "grounded")
if input.skiing:
mesh.animation_tree.set("parameters/locomotion/blend_position", Vector2.ZERO)
mesh.animation_tree.set("parameters/mix/blend_amount", .0)
@ -341,7 +309,7 @@ func _animate_third_person() -> void:
var blend:float = mesh.animation_tree["parameters/mix/blend_amount"]
mesh.animation_tree.set("parameters/mix/blend_amount", lerp(blend, input.direction.length(), .5))
else:
mesh.animation_tree.set("parameters/transition/transition_request", &"mid_air")
mesh.animation_tree.set("parameters/transition/transition_request", "mid_air")
## This method returns wether the local system multiplayer peer has input authority over this node
func is_pawn() -> bool:

File diff suppressed because one or more lines are too long