b0c83af092
Complete replacement of the tactical-shooter project with the netfox-cs-sample (MIT) — a CS 1.6 inspired multiplayer FPS built with Godot 4 and netfox. ## What's new - Full CS-style gameplay: teams (T/CT), rounds, economy, buy menu - 6 weapons: Knife, Glock, USP, AK-47, M4A1, AWP - Bomb plant/defuse with 2 bombsites - Flashbang & smoke grenades - Proper netfox rollback netcode at 64 tick - Network popup UI for host/join - HUD, crosshair, round timer, scoreboard - All netfox singletons registered as autoloads (works in exported builds) ## Architecture - Listen-server (host from client, no dedicated server binary) - Multiplayer-fps game lives at examples/multiplayer-fps/ - Netfox addons registered as autoloads for exported build compat - Godot 4.7 with Forward+ renderer ## Removed - Old headless-server architecture (client_main, server_main, player.gd, etc.) - Custom netfox bootstrap with ENet fallback - Old ChaffGames FPS template (2,420 lines, 844 KB) - SimulationServer GDExtension stub - Godot-jolt physics (netfox sample uses default Godot physics) - Duplicate weapon_data.gd, anti_cheat.gd, round_manager.gd, etc. - Server browser API Python venv (87 MB) - test_range map and modular assets ## Preserved - Git history - Server config at config/default_server_config.cfg - Windows export preset - Build directory (gitignored) Co-authored-by: naxIO <naxIO@users.noreply.github.com>
92 lines
2.5 KiB
GDScript
92 lines
2.5 KiB
GDScript
extends BaseNetInput
|
|
class_name BrawlerInput
|
|
|
|
@export var switch_time: float = 1.0
|
|
var camera: Camera3D
|
|
|
|
@onready var _player: Node3D = get_parent()
|
|
@onready var _confine_mouse: bool = DisplayServer.mouse_get_mode() == DisplayServer.MOUSE_MODE_CONFINED
|
|
|
|
var movement: Vector3 = Vector3.ZERO
|
|
var aim: Vector3 = Vector3.ZERO
|
|
var is_firing: bool = false
|
|
|
|
var _last_mouse_input: float = 0.0
|
|
var _aim_target: Vector3
|
|
var _projected_target: Vector3
|
|
var _has_aim: bool = false
|
|
|
|
func _input(event):
|
|
if event is InputEventMouse:
|
|
_last_mouse_input = NetworkTime.local_time
|
|
|
|
func _gather():
|
|
# Movement
|
|
movement = Vector3(
|
|
Input.get_axis("move_west", "move_east"),
|
|
Input.get_action_strength("move_jump"),
|
|
Input.get_axis("move_north", "move_south")
|
|
)
|
|
|
|
# Aim
|
|
aim = Vector3(
|
|
Input.get_axis("aim_west", "aim_east"),
|
|
0.0,
|
|
Input.get_axis("aim_north", "aim_south")
|
|
)
|
|
|
|
if aim.length():
|
|
# Prefer gamepad
|
|
# Reset timeout for mouse motion
|
|
_last_mouse_input = NetworkTime.local_time - switch_time
|
|
elif NetworkTime.local_time - _last_mouse_input > switch_time:
|
|
# Use movement if no mouse motion recently
|
|
aim = movement
|
|
elif _has_aim:
|
|
# Use mouse raycast
|
|
aim = (_aim_target - _player.global_position).normalized()
|
|
else:
|
|
# Fall back to mouse projected to player height
|
|
aim = (_projected_target - _player.global_position).normalized()
|
|
|
|
# Always aim horizontally, never up or down
|
|
aim.y = 0
|
|
aim = aim.normalized()
|
|
|
|
# Hide mouse if inactive
|
|
if NetworkTime.local_time - _last_mouse_input >= switch_time:
|
|
DisplayServer.mouse_set_mode(
|
|
DisplayServer.MOUSE_MODE_CONFINED_HIDDEN if _confine_mouse else DisplayServer.MOUSE_MODE_HIDDEN
|
|
)
|
|
else:
|
|
DisplayServer.mouse_set_mode(
|
|
DisplayServer.MOUSE_MODE_CONFINED if _confine_mouse else DisplayServer.MOUSE_MODE_VISIBLE
|
|
)
|
|
|
|
is_firing = Input.is_action_pressed("weapon_fire")
|
|
|
|
func _physics_process(_delta):
|
|
if not camera:
|
|
camera = get_viewport().get_camera_3d()
|
|
|
|
# Aim
|
|
var mouse_pos = get_viewport().get_mouse_position()
|
|
var ray_origin = camera.project_ray_origin(mouse_pos)
|
|
var ray_normal = camera.project_ray_normal(mouse_pos)
|
|
var ray_length = 128
|
|
|
|
var space = camera.get_world_3d().direct_space_state
|
|
var hit = space.intersect_ray(PhysicsRayQueryParameters3D.create(
|
|
ray_origin, ray_origin + ray_normal * ray_length
|
|
))
|
|
|
|
if not hit.is_empty():
|
|
# Aim at raycast hit
|
|
_aim_target = hit.position
|
|
_has_aim = true
|
|
else:
|
|
# Project to player's height
|
|
var height_diff = _player.global_position.y - ray_origin.y
|
|
_projected_target = ray_origin + ray_normal * (height_diff / ray_normal.y)
|
|
_has_aim = false
|