diff --git a/client/Global.gd b/client/Global.gd index 762d4db..0a3e20b 100644 --- a/client/Global.gd +++ b/client/Global.gd @@ -11,6 +11,6 @@ var terrain: Terrain3D var instance_id: int func _enter_tree(): - instance_id = OS.get_process_id() % 2 + instance_id = 0 #OS.get_process_id() % 2 account = Account.new() account.name = "user%d" % instance_id diff --git a/client/network/PlayerJump.gd b/client/network/PlayerJump.gd index 056d555..70a3969 100644 --- a/client/network/PlayerJump.gd +++ b/client/network/PlayerJump.gd @@ -17,4 +17,8 @@ func on_jump(): func handle_packet(data: PackedByteArray): var player_id := data.get_string_from_ascii() var player := Global.players.get_player(player_id) + + if !player: + return + player.controller.jumped.emit() diff --git a/client/player/animation/AnimationComponent.gd b/client/player/animation/AnimationComponent.gd index fb3abac..4908272 100644 --- a/client/player/animation/AnimationComponent.gd +++ b/client/player/animation/AnimationComponent.gd @@ -1,12 +1,10 @@ class_name AnimationComponent extends CharacterComponent -@export var skip_frames: int = 0 - var animations: AnimationPlayer var state: StateComponent var accumulated_delta: float -var skipped_frames: int +var delay: float func _ready(): state = character.get_node("State") @@ -16,12 +14,9 @@ func _ready(): func _process(delta: float): accumulated_delta += delta - if skipped_frames >= skip_frames: + if accumulated_delta >= delay: animations.advance(accumulated_delta) accumulated_delta = 0 - skipped_frames = 0 - else: - skipped_frames += 1 func on_transition(_from: StateComponent.State, to: StateComponent.State): match to: diff --git a/client/player/footsteps/FootstepsComponent.gd b/client/player/footsteps/FootstepsComponent.gd index f98fb33..a57a180 100644 --- a/client/player/footsteps/FootstepsComponent.gd +++ b/client/player/footsteps/FootstepsComponent.gd @@ -15,8 +15,7 @@ var ik_time: float func _ready(): if owner != Global.player: - queue_free() - return + set_enabled(false) for foot_name in feet_names: var foot = Foot.new() @@ -94,3 +93,7 @@ func get_foot_rotation(old: Basis, normal: Vector3) -> Basis: new = new.orthonormalized() new = new.rotated(Vector3.UP, PI) return new + +func set_enabled(enabled: bool): + set_process(enabled) + set_physics_process(enabled) diff --git a/client/player/movement/MovementComponent.gd b/client/player/movement/MovementComponent.gd index 8656e95..8c2f65f 100644 --- a/client/player/movement/MovementComponent.gd +++ b/client/player/movement/MovementComponent.gd @@ -17,6 +17,9 @@ func _ready(): character.controlled.connect(on_controlled) func _process(delta: float): + if (physics_position - character.position).length_squared() < 0.00001: + return + character.position = Math.damp_vector(character.position, physics_position, ticks_per_second * delta) func _physics_process(delta: float): diff --git a/client/player/performance/AnimationPerformance.gd b/client/player/performance/AnimationPerformance.gd new file mode 100644 index 0000000..20fd2b0 --- /dev/null +++ b/client/player/performance/AnimationPerformance.gd @@ -0,0 +1,36 @@ +class_name AnimationPerformance + +const DELAY_INVISIBLE := 1.0 +const DELAY_VISIBLE := 0.5 + +static var quality_budget: Array[int] = [ + 10, # Full animation quality + 5, # 2.5 ms delay + 5, # 5.0 ms delay + 5, # 7.5 ms delay + 5, # 10.0 ms delay + 5, # 12.5 ms delay + 5, # 15 ms delay + 5, # 17.5 ms delay + 5, # 20 ms delay +] + +static func update_animation_quality(visible_players: Array[Player]): + var delay := 0.0 + var count := 0 + var index := 0 + + for player in visible_players: + if index >= quality_budget.size(): + player.performance.delay_visible = DELAY_VISIBLE + player.animation.delay = DELAY_VISIBLE + continue + + player.performance.delay_visible = delay + player.animation.delay = delay + count += 1 + + if count >= quality_budget[index]: + index += 1 + delay += 0.025 + count = 0 \ No newline at end of file diff --git a/client/player/performance/PerformanceComponent.gd b/client/player/performance/PerformanceComponent.gd index 93a5ffb..8cbfd5b 100644 --- a/client/player/performance/PerformanceComponent.gd +++ b/client/player/performance/PerformanceComponent.gd @@ -1,25 +1,11 @@ class_name PerformanceComponent extends VisibleOnScreenNotifier3D -const SKIP_FRAMES_INVISIBLE := 16 -const SKIP_FRAMES_VISIBLE := 8 - -static var quality_budget: Array[int] = [ - 10, # 0 skipped frames - 10, # 1 skipped frame - 10, # 2 skipped frames - 10, # 3 skipped frames - 10, # 4 skipped frames - 10, # 5 skipped frames - 10, # 6 skipped frames - 10, # 7 skipped frames -] - @export var animation: AnimationComponent var camera_distance_squared: float var on_screen: bool -var skip_frames_visible: int +var delay_visible: float func _ready(): assert(animation) @@ -28,13 +14,13 @@ func _ready(): func on_screen_entered(): on_screen = true - animation.skip_frames = skip_frames_visible + animation.delay = delay_visible func on_screen_exited(): on_screen = false - animation.skip_frames = SKIP_FRAMES_INVISIBLE + animation.delay = AnimationPerformance.DELAY_INVISIBLE -static func update_all_animations(): +static func get_visible_players_sorted_by_distance() -> Array[Player]: var visible_players: Array[Player] = [] for player in Global.players.id_to_player.values(): @@ -43,30 +29,13 @@ static func update_all_animations(): if player.performance.on_screen: visible_players.append(player) else: - player.performance.animation.skip_frames = SKIP_FRAMES_INVISIBLE + player.performance.animation.delay = AnimationPerformance.DELAY_INVISIBLE if Global.player: Global.player.performance.camera_distance_squared = 0 visible_players.sort_custom(PerformanceComponent.distance_sort) - - var skip_frames := 0 - var count := 0 - - for player in visible_players: - if skip_frames >= quality_budget.size(): - player.performance.skip_frames_visible = SKIP_FRAMES_VISIBLE - player.animation.skip_frames = SKIP_FRAMES_VISIBLE - continue - - player.performance.skip_frames_visible = skip_frames - player.animation.skip_frames = skip_frames - count += 1 - - if count >= quality_budget[skip_frames]: - skip_frames += 1 - count = 0 + return visible_players static func distance_sort(a: Player, b: Player) -> bool: - return a.performance.camera_distance_squared < b.performance.camera_distance_squared - \ No newline at end of file + return a.performance.camera_distance_squared < b.performance.camera_distance_squared \ No newline at end of file diff --git a/client/world/PlayerManager.gd b/client/world/PlayerManager.gd index e319efe..3df407f 100644 --- a/client/world/PlayerManager.gd +++ b/client/world/PlayerManager.gd @@ -10,7 +10,8 @@ func _ready(): timer.timeout.connect(tick) func tick(): - PerformanceComponent.update_all_animations() + var visible_players := PerformanceComponent.get_visible_players_sorted_by_distance() + AnimationPerformance.update_animation_quality(visible_players) func add(player: Player): if has(player.id): @@ -20,7 +21,7 @@ func add(player: Player): id_to_player[player.id] = player func get_player(id: String) -> Player: - return id_to_player[id] as Player + return id_to_player.get(id) as Player func has(id: String) -> bool: return id_to_player.has(id) diff --git a/server/game/Database.go b/server/game/Database.go index 0359fac..4d87714 100644 --- a/server/game/Database.go +++ b/server/game/Database.go @@ -7,7 +7,7 @@ import ( ) var ( - SpawnPoint = Vector3{584.98, 9.5, 394.68} + SpawnPoint = Vector3{584.98, 9.8, 394.68} accounts = map[string]*Account{} ) @@ -19,7 +19,7 @@ func init() { func MakeTestAccounts() { for i := range 500 { angle := rand.Float64() * math.Pi * 2 - distance := rand.Float64() * 12.0 + distance := rand.Float64() * 25.0 accounts[fmt.Sprintf("user%d", i)] = &Account{ ID: fmt.Sprintf("id%d", i),