From a69c60ce85bdaa6f38a0e04abc7373a98c10a8dd Mon Sep 17 00:00:00 2001 From: Shawn Date: Thu, 2 Jul 2026 18:17:05 -0400 Subject: [PATCH] Fix Windows build: use entry.tscn as main scene, add fallback input handling - Changed run/main_scene to entry.tscn (smart bootstrap detects headless vs display) - client_main.gd now uses player.tscn instead of old FPS template - Added mouse look (click-to-capture, escape-to-release) to player.gd fallback path - Added _gather() call to player.gd fallback _physics_process() so PlayerNetInput is populated even without NetworkTime singleton (exported builds) - Re-exported Windows build with same tag v0.1.0-windows --- project.godot | 2 +- scripts/network/client_main.gd | 2 +- scripts/network/player.gd | 56 ++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/project.godot b/project.godot index f12db01..4ea4a39 100644 --- a/project.godot +++ b/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="Tactical Shooter" config/description="Phase 0 — Headless Dedicated Server" -run/main_scene="res://scenes/server/server_main.tscn" +run/main_scene="res://scenes/entry.tscn" config/features=PackedStringArray("4.7", "Forward Plus") [autoload] diff --git a/scripts/network/client_main.gd b/scripts/network/client_main.gd index aeecba4..11a84f1 100644 --- a/scripts/network/client_main.gd +++ b/scripts/network/client_main.gd @@ -16,7 +16,7 @@ extends Node3D # --------------------------------------------------------------------------- @export var server_host: String = "68.202.6.107" @export var server_port: int = 34197 -@export var fps_scene: PackedScene = preload("res://client/template/player_character.tscn") +@export var fps_scene: PackedScene = preload("res://scenes/player.tscn") # --------------------------------------------------------------------------- # State diff --git a/scripts/network/player.gd b/scripts/network/player.gd index 4b8cc98..7f08cb5 100644 --- a/scripts/network/player.gd +++ b/scripts/network/player.gd @@ -109,22 +109,72 @@ func _ready() -> void: print("[Player] Remote player: %d (authority: %d) — rollback sync" % [ multiplayer.get_unique_id(), multiplayer.get_multiplayer_authority()]) else: - # No RollbackSynchronizer (headless/server mode). + # No RollbackSynchronizer (headless/server mode or exported build). # Enable _physics_process as fallback simulation. set_physics_process(true) + # Enable _input for mouse look when this is the local player + set_process_input(is_local) print("[Player] Player %d — rollback not available, using fallback physics" % multiplayer.get_unique_id()) +# --------------------------------------------------------------------------- +# Input (mouse look) — used only in fallback mode (no rollback sync) +# --------------------------------------------------------------------------- + +## Mouse look variables for fallback mode. +var _mouse_look_sensitivity: float = 0.003 +var _mouse_look_invert_y: bool = false +var _mouse_captured: bool = false + +## Handle mouse input for looking around in fallback mode. +## Only active when set_process_input(true) was called in _ready. +func _input(event: InputEvent) -> void: + if not is_local or _rollback_sync != null: + return + + # Mouse look + if event is InputEventMouseMotion and _mouse_captured: + var rel: Vector2 = event.relative + _yaw -= rel.x * _mouse_look_sensitivity + var invert: float = -1.0 if _mouse_look_invert_y else 1.0 + _pitch += rel.y * _mouse_look_sensitivity * invert + _pitch = clamp(_pitch, deg_to_rad(-89.0), deg_to_rad(89.0)) + + # Click to capture mouse + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + if not _mouse_captured: + _capture_mouse_fallback(true) + +func _unhandled_input(event: InputEvent) -> void: + if not is_local or _rollback_sync != null: + return + # Escape to release mouse + if event.is_action_pressed("ui_cancel"): + _capture_mouse_fallback(false) + +func _capture_mouse_fallback(capture: bool) -> void: + if capture == _mouse_captured: + return + _mouse_captured = capture + if capture: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + else: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + # --------------------------------------------------------------------------- # Fallback physics — used when RollbackSynchronizer is not available -# (e.g., headless dedicated server without netfox singletons). +# (e.g., headless dedicated server without netfox singletons, or exported builds). # --------------------------------------------------------------------------- func _physics_process(delta: float) -> void: # Only run fallback if RollbackSynchronizer is NOT handling ticks if _rollback_sync != null: return - # Read input from PlayerNetInput (if we're the authority) + # Gather current frame input into PlayerNetInput (standalone mode) var input_node = _find_input_node() + if input_node != null and input_node.has_method(&"_gather"): + input_node._gather() + + # Read input from PlayerNetInput (if we're the authority) if input_node == null: return