P23-03: 生活の観察
This commit is contained in:
+28
-5
@@ -12,25 +12,35 @@ class MotionObserver extends Node:
|
||||
var scaled_elapsed := 0.0
|
||||
func _ready() -> void:
|
||||
RenderingServer.frame_post_draw.connect(after_draw)
|
||||
view.draw.connect(on_view_draw)
|
||||
func _process(delta: float) -> void:
|
||||
elapsed += delta
|
||||
var clock := get_node_or_null("/root/GameClock")
|
||||
if clock == null or not bool(clock.get("paused")):
|
||||
scaled_elapsed += delta * maxf(float(clock.get("speed")) if clock != null else 1.0, 0.0)
|
||||
func after_draw() -> void:
|
||||
if not is_instance_valid(view): return
|
||||
var report := view.get_life_observation_report()
|
||||
if report.is_empty(): return
|
||||
func on_view_draw() -> void:
|
||||
# Read the draw-consumed report after the real _draw completes.
|
||||
after_draw.call_deferred()
|
||||
func display_sample(report: Dictionary) -> Dictionary:
|
||||
var sample := {}
|
||||
for key: String in ["animation_time", "paused", "layer", "zoom", "pan", "viewport", "actor_tracks", "elevator_tracks", "actor_drawings", "cabins"]:
|
||||
sample[key] = report[key]
|
||||
return sample
|
||||
func after_draw() -> void:
|
||||
if not is_instance_valid(view): return
|
||||
var frame := Engine.get_process_frames()
|
||||
if not frames.is_empty() and frame <= int(frames[-1]["frame"]): return
|
||||
var report := view.get_life_observation_report()
|
||||
if report.is_empty(): return
|
||||
var sample := display_sample(report)
|
||||
if not frames.is_empty() and sample == frames[-1]["display"] and not sample["paused"]: return
|
||||
# Keep only two draw frames, never whole Runtime copies per frame.
|
||||
frames.append({"frame": Engine.get_process_frames(), "delta": elapsed, "scaled_delta": scaled_elapsed, "display": sample})
|
||||
frames.append({"frame": frame, "delta": elapsed, "scaled_delta": scaled_elapsed, "display": sample})
|
||||
if frames.size() > 2: frames.pop_front()
|
||||
elapsed = 0.0
|
||||
scaled_elapsed = 0.0
|
||||
func _exit_tree() -> void:
|
||||
if is_instance_valid(view) and view.draw.is_connected(on_view_draw): view.draw.disconnect(on_view_draw)
|
||||
if RenderingServer.frame_post_draw.is_connected(after_draw): RenderingServer.frame_post_draw.disconnect(after_draw)
|
||||
|
||||
func watch(view: WorldPreview) -> void:
|
||||
@@ -38,6 +48,19 @@ func watch(view: WorldPreview) -> void:
|
||||
observer.view = view
|
||||
view.add_child(observer)
|
||||
|
||||
func await_draws(tree: SceneTree, view: WorldPreview, n: int = 2, bound: int = 120) -> bool:
|
||||
var start := Engine.get_process_frames()
|
||||
for unused: int in range(bound):
|
||||
view.queue_redraw()
|
||||
await tree.process_frame
|
||||
if not is_instance_valid(observer): break
|
||||
var report := view.get_life_observation_report()
|
||||
if observer.frames.size() == n and not report.is_empty() and int(observer.frames[0]["frame"]) > start and observer.frames[-1]["display"] == observer.display_sample(report):
|
||||
return true
|
||||
# Persist timeout as a failure, never a skip.
|
||||
record("draw-history-timeout", {"start_frame": start, "bound": bound, "required_frames": n})
|
||||
return false
|
||||
|
||||
func open(path: String) -> bool:
|
||||
directory = path
|
||||
if DirAccess.dir_exists_absolute(path):
|
||||
|
||||
Reference in New Issue
Block a user