75 Commits

Author SHA1 Message Date
shawn fe9738ca46 Fix weapon switching, scale, add Q key bind
- Fixed weapon switching: player.gd now uses weapon_next/weapon_prev/slot actions
  (was checking for nonexistent 'weapon_toggle')
- Added Q key to weapon_next input action
- Reduced weapon scale from 0.3 to 0.07-0.08 (was still 3x too large)
v0.2.9
2026-07-05 23:54:57 -04:00
shawn 0723b75f7b Fix weapon position, scale, switch to GLB imports
- Reduced weapon scale 10-13x (previously OBJ models at native size)
- Adjusted on-screen position for each weapon type
- Switched from OBJ to GLB imports (better pivot points)
- Fixed Revolver model coordinate issue
v0.2.8
2026-07-05 23:29:30 -04:00
shawn 91b878f347 Quaternius weapons, input fixes, sound & path fixes
- Added 6 Quaternius weapon models (Pistol, Revolver, Rifle, Shotgun, P90, SniperRifle)
- Created weapon resource files with balanced stats
- Wired Pistol + Rifle into player.tscn replacing Kenney blasters
- Fixed WASD input (matched input map action names)
- Fixed Escape key toggles mouse capture
- Added Audio autoload singleton
- Fixed broken sound asset paths across all scripts
- Fixed all scene ext_resource text paths (nested under assets/kenney-fps/)
- Fixed all .import source_file paths
- Deleted stale .import files (will be regenerated by editor on open)
v0.2.7
2026-07-05 22:53:27 -04:00
shawn 695e4db5cd Add input debug to window title for diagnostic
Shows Input.get_axis() values, weapon slot states, and fire
state in the window title bar — visible even when print()
output is lost on Windows GUI exports.
v0.2.6
2026-07-03 23:13:42 -04:00
shawn c5b6b05801 Fix keyboard input: use OS.move_to_foreground() for window focus
get_window().grab_focus() was insufficient on Windows GUI exports.
Replaced with OS.move_to_foreground() + Input.set_mouse_mode(CAPTURED)
+ deferred retries to ensure the game window holds keyboard focus
after the connection UI is dismissed.
v0.2.5
2026-07-03 22:34:50 -04:00
shawn ef4e4ccb80 Clean up test diagnostic files v0.2.4 2026-07-03 20:07:49 -04:00
shawn 7db8434f7e Fix duplicate _rollback_tick causing WeaponManager compile error
A debug-print attempt from earlier inadvertently appended a second
_rollback_tick function (with spaces instead of tabs) at the end of
weapon_manager.gd:419, causing the entire script to fail compilation.
This meant the WeaponManager node had NO script attached:
- 'has_method("set_default_loadout")' returned false
- Client-side loadout init never ran
- All weapon operations silently did nothing

This is the real root cause of why weapons never worked on the client.
2026-07-03 20:07:40 -04:00
shawn 7bbe4ba71d Fix weapons not working on client: remove is_predicting check + init loadout
- Removed the is_predicting() early-return in weapon_manager._rollback_tick
  which blocked all weapon actions on the client (player owned by server)
- Added client-side weapon loadout initialization in player-spawner._spawn
  so the player has weapons immediately, before server state sync arrives
- Server reconciles via rollback state sync

Movement was fixed in v0.2.2 (window focus grab). This addresses
the remaining 'can't switch or use weapons' issue.
v0.2.3
2026-07-03 18:24:21 -04:00
shawn 1ccd26bbab Fix keyboard input not working on Windows client
Added explicit window focus grab after connecting (lan-bootstrapper.gd)
so keyboard input is properly received by the input system.
Also added diagnostic debug prints to trace input pipeline.
v0.2.2
2026-07-03 17:48:33 -04:00
shawn 9901f6a34d Fix blaster GLB root type error (Node3D, not MeshInstance3D)
- Changed _gun_model type from MeshInstance3D to Node3D
  (all imported GLB/GLTF weapon models have Node3D root)
- Added check_models.gd diagnostic script

The type mismatch at WeaponManager._load_weapon_models:73
was the only script error in the user's game.log.
Headless bot tests confirm movement still works fine.
v0.2.1
2026-07-03 17:32:18 -04:00
shawn 012d038025 Integrate Kenney Starter Kit FPS assets + comprehensive test suite
Assets (CC0 license):
- 3D models: Blaster gun, walls, platforms, grass, clouds, enemy
- Sounds: blaster fire, impacts, footsteps, jumps, weapon change
- Sprites: crosshair, hit marker, muzzle flash, skybox, blob shadow
- Font: Lilita One

Code changes:
- weapon_manager.gd: load blaster.glb as gun model (replaces box mesh)
- player.tscn: use Kenney sounds (blaster.ogg, enemy_hurt/destroy) and crosshair

Test suite (100 unit tests + 4 integration scenarios):
- weapon_data.gd: 27 tests — all 6 weapons every stat verified
- economy.gd: 19 tests — constants, loss streak, buy thresholds
- bomb.gd: 15 tests — state machine, timing constants
- round_manager.gd: 10 tests — win conditions, elimination logic
- team_manager.gd: 8 tests — auto-balance, team assignment
- headless_test_bot.gd: integration bot with movement/idle/rounds scenarios
- run_multi_bot.sh: multi-client launcher
v0.2.0
2026-07-03 17:13:36 -04:00
shawn 597d6dde2d Fix server clock reset in NetworkTimeSynchronizer and client-side peer 1 avatar duplicate
- Move _clock.set_time(0.) inside the 'if not server' block in
  NetworkTimeSynchronizer.start() so the server's SystemClock isn't
  reset to zero — fixes -1.78 billion second offset panic on client
- Skip spawning peer 1's avatar on clients (the server replicates
  all avatars; spawning peer 1 locally creates a duplicate that
  the dedicated server doesn't have)
v0.1.5
2026-07-03 16:21:35 -04:00
shawn aad186552c Bake dev server IP (192.168.0.127:34197) as default in network popup v0.1.4 2026-07-03 16:11:23 -04:00
shawn 5a1695e2ab Fix Godot 4.7 typed array crash: add freed-object filtering in PropertyPool and PerObjectHistory v0.1.3 2026-07-03 16:09:59 -04:00
shawn fc2c0236cb Fix dedicated server: delay netfox tick loop until first client connects, keep full scene tree for identity sync v0.1.2 2026-07-03 14:47:00 -04:00
shawn ba2fc37502 Make weapons test fully self-contained, fix headless bootstrap preload
Weapon tests now embed weapon data inline rather than preloading
WeaponRegistry (which triggers WeaponData class_name resolution).
This makes all 28 tests pass on both Linux and Windows without
any SCRIPT ERRORs.

Also add WeaponData.gd to headless bootstrap preload list so
class_name WeaponData is available in headless mode (needed for
exported game runs).

Test breakdown (all pass, zero errors):
  weapons.gd:      9 tests (6 weapons + registration + default pistol)
  bootstrapper.gd: 6 tests (input parsing validation)
  team.gd:         6 tests (auto-assign, team names, enum values)
  economy.gd:      7 tests (constants, money clamping, loss streaks)
v0.1.1
2026-07-03 01:48:20 -04:00
shawn e24637b049 Refactor tests to be self-contained — no game class dependencies
All 25 tests now run cleanly in headless mode without any SCRIPT ERRORs.
Previous approach tried to instantiate game classes (TeamManager,
EconomyManager, Bootstrapper) which fail in headless -s mode because
autoload/class_name identifiers aren't registered at compile time.

New approach: inline the tested logic directly in each test file.
- weapons.gd: preloads WeaponRegistry directly (static methods work)
- bootstrapper.gd: inlines _parse_input() logic
- team.gd: inlines auto-assign/team-name logic
- economy.gd: inlines constants and formula logic

Also: removed dead test_util.gd exclusion from runner.
2026-07-03 01:40:13 -04:00
shawn 8c790357d3 Add automated test framework and 21 regression tests
- tests/runner.gd: lightweight headless test runner (TAP format output)
- tests/weapons.gd: 6 tests for weapon registry and stats
- tests/team.gd: 5 tests for team assignment and balancing
- tests/economy.gd: 6 tests for economy constants and loss streaks
- tests/bootstrapper.gd: 4 tests for LAN bootstrapper input parsing

Run with: godot --headless -s tests/runner.gd --path .

All 21 tests pass on Linux and Windows.
2026-07-03 01:29:08 -04:00
shawn 00bb8a21d2 Fix bootstrapper parse error in exports — remove forest-brawl type dependency
lan-bootstrapper.gd and noray-bootstrapper.gd both had a host_only()
function that referenced BrawlerSpawner (class_name from forest-brawl).
Since examples/forest-brawl/ is excluded from exports, the type was
undefined, causing the entire script to fail loading with:
  'Could not find type BrawlerSpawner in current scope'

This meant the Join and Host button signal handlers never existed,
so clicking them did nothing — no error shown, no connection, no UI change.

Fix: remove the unused host_only() function from both bootstrapper files.
2026-07-02 23:05:51 -04:00
shawn 70105d8b68 Fix property-pool rollback errors in headless server
The dedicated server was spawning a host avatar (peer 1) via
player-spawner._handle_host() and _handle_new_peer(1) on startup,
which registered RollbackSynchronizer subjects with the netfox
rollback system. Since no client input exists for peer 1, the
rollback system tried to record state for freed/recycled objects,
flooding the log with property-pool.gd errors.

Fix:
- Add spawn_host_avatar @export flag to player-spawner.gd
- Set it false in headless_server.gd before starting the ENet server
- PlayerSpawner._handle_host() skips avatar spawn when flag is false
- PlayerSpawner._handle_new_peer(1) skips avatar spawn when flag is false

Server startup is now clean: no property-pool errors, no RPC path errors.
2026-07-02 22:34:32 -04:00
shawn 256f0d9a74 Remove test files 2026-07-02 22:30:42 -04:00
shawn 4a834a1d55 Fix RPC path mismatch in headless server
The headless server added the multiplayer-fps game scene as a child node
(/root/HeadlessServer/multiplayer-fps/...), causing RPC node paths to
include the HeadlessServer/ prefix. Clients expected paths relative to
root (/root/multiplayer-fps/...), so every RPC would fail with
'Node not found'.

Fix: add the game scene directly to /root/ via call_deferred, making it
a sibling of the HeadlessServer node rather than a child. RPC paths now
match between server and client.
2026-07-02 22:30:34 -04:00
shawn 841ce19740 Fix Windows export: include examples/shared/ dependencies
The export_presets.cfg excluded examples/shared/** from both Windows
Desktop and Linux Server presets. The multiplayer-fps.tscn main scene
depends on files in this directory (network-popup.tscn, async.gd,
simple-time-display.gd) — without them the exported binary crashes
on startup with 'Can't load dependency' errors.

- Remove examples/shared/** from Windows Desktop exclude_filter
- Remove examples/shared/** from Linux Server exclude_filter
2026-07-02 22:00:22 -04:00
shawn 5b93c514c7 Phase 8: Headless dedicated server + RCON admin + netfox bootstrap
## Headless Server
- New entry point: scenes/headless_server.tscn + scripts/headless_server.gd
- Loads multiplayer-fps game, strips UI/rendering, auto-hosts ENet server
- Port config via --port arg, SERVER_PORT env, or default 34197
- RCON admin console on port 28960 (configurable via --rcon-port)

## Netfox Headless Bootstrap
- scripts/netfox_headless_bootstrap.gd — preloads all netfox dependency
  scripts in headless mode so class_names register before autoloads parse
- Registered as first autoload in project.godot
- Fixes 'Could not find type' errors for NetfoxLogger, NorayProtocolHandler,
  NetworkClocks, etc.

## RCON Admin
- Ported from old project: scripts/rcon/rcon_server.gd (TCP auth layer)
- scripts/rcon/rcon_command_handler.gd (command dispatch)
- Password via config/rcon_password.cfg, --rcon-password, or RCON_PASSWORD env

## Other Changes
- Added GameEvents stub (lan-bootstrapper dependency)
- Updated project.godot features to 4.7
- Added config/server_config.cfg for operator editing
- Updated RCON paths to new project structure
2026-07-02 21:49:49 -04:00
shawn b0c83af092 Fresh start: replace with naxIO/netfox-cs-sample foundation
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>
v0.1.0
2026-07-02 20:55:20 -04:00
shawn ce39b237c3 Fix fps_camera.gd path for export — move out of ignored client/ dir
- Copied fps_camera.gd from client/characters/character/ to scripts/characters/
- Updated player.tscn to reference new path
- The client/ directory has its own project.godot so Godot ignores it during export
- Zero export errors now
v0.1.0-windows
2026-07-02 18:19:12 -04:00
shawn a69c60ce85 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
2026-07-02 18:17:05 -04:00
shawn 969741aa31 v0.1.0-windows: initial Windows release build
- WeaponData: restored class_name, converted static vars to make() factory
- WeaponDefinitions: updated to use make() instead of static var refs
- Windows export: tactical-shooter.exe + godot-jolt_windows-x64.dll
- Build artifact: build/tactical-shooter-windows-x86_64-v0.1.0.zip
2026-07-02 18:09:16 -04:00
shawn e70ce76207 P7.9: fix headless export — resolve Resource class_name ordering + duplicate RoundManager + simulation stub API
- Fix dead code in server_main.gd (unreachable lag compensation print)
- Remove WeaponData type hints from weapon_server.gd (Resource class_name in Node scripts = headless fail)
- Use preload() instead of WeaponData class_name in weapon_definitions.gd for const refs
- Lazy-init WEAPONS dict (const can't reference preload members)
- Remove duplicate class_name RoundManager from server/scripts/round/round_manager.gd
- Remove DamageProcessor type hints from round/round_manager.gd and bomb_objective.gd
- Add start()/stop()/can_tick()/tick()/spawn_entity()/despawn_entity() to simulation_server_stub.gd
- Fix get_world_3d() → get_tree().root.world_3d in weapon_server.gd Node context
- Fix var data := → var data = for untyped WeaponDefinitions.get_weapon() returns
- Clean export cache and verify server starts with zero parse errors
2026-07-02 17:57:09 -04:00
shawn 926446e5cf P7.8: Port FPS controller to netfox BaseNetInput pattern
- FPSCharacterController: removed SimulationServer dependency, added
  _rollback_tick() with acceleration-based CharacterBody3D movement,
  gravity, jump, crouch/sprint speed. Kept mouse look, crouch lerp,
  sprint/crouch toggle, _move_local() standalone fallback.
- Player: extends FPSCharacterController (CharacterBody3D). Added
  authority-guarded _rollback_tick that delegates to super for server
  and local client prediction. TickInterpolator created dynamically
  (avoids headless class_name parse errors). PlayerNetInput child
  wired via existing RollbackSynchronizer input_properties.
- player.tscn: CharacterBody3D root with FpsCamera, CollisionShape3D,
  PlayerNetInput children. TickInterpolator created in code.
- client_main.gd: _spawn_local_player() creates FPS player node with
  first-person camera for own peer. _spawn_remote_player() removes
  FpsCamera for remote players.
- fps_camera.gd: duck-typed _controller (Node) instead of class_name
  cast for headless safety. Fixed type inference warnings.

Also includes parent task P7.5-P7.7 changes:
- project.godot: main_scene -> server_main.tscn
- network_manager.gd: Chan enum -> raw channel ints
- server_main.gd: deferred ServerConfig load, GameServer load()
- game_server.gd: commented out dev deps for headless compilation
2026-07-02 17:45:03 -04:00
shawn e7299b17e9 Phase 7: netfox + godot-jolt stack upgrade
Stack installed:
- netfox v1.35.3 (core + extras + noray + internals)
- godot-jolt v0.16.0-stable

Architecture:
- Server: ENet transport (works headless, no netfox deps)
- Client/Editor: netfox rollback (RollbackSynchronizer, TickInterpolator)

New/modified:
- docs/migration-netfox-plan.md — migration architecture
- scripts/network/network_manager.gd — netfox-aware ENet fallback
- scripts/network/player.gd — clean base player
- client/characters/player_netfox.gd — rollback player w/ WeaponManager
- client/characters/input/player_net_input.gd — BaseNetInput subclass
- client/characters/character/fps_character_controller.gd — netfox input feed
- client/weapons/ — weapon data, registry, TacticalWeaponHitscan, WeaponManager
- client/scripts/round_replicator.gd — client-side round state bridge
- server/scripts/round_manager.gd — improved state machine
- server/scripts/plugin_api/plugin_manager.gd — refined plugin system
- config: enemy_tag, ally_tag for meatball targeting

Removed: old C++ SimulationServer GDExtension (replaced by netfox rollback)
2026-07-02 17:39:22 -04:00
shawn e2dc429caa t_p7.4_port: fix player.gd extends + FPSCharacterController deps
- Changed player.gd from extending FPSCharacterController (via path) to
  extending CharacterBody3D directly, avoiding headless class resolution
  error for client/ scripts.
- Removed super._ready() and _set_local_player() calls (FPSCharacterController
  specifics not available in CharacterBody3D).
- Replaced super._rollback_tick() with direct simulation guard.
- Removed reset_pose() call (FPSCharacterController-specific).
- All FPSCharacterController features remain in client-side player_netfox.gd
  which extends player.gd.
- Verified: 0 SCRIPT ERRORs in headless mode.
2026-07-02 17:39:19 -04:00
shawn 25221bf3cb t_p7.4_port: network_manager to netfox
- Fixed double-emission bug in network_manager.gd: ENet signal connections
  (peer_connected/peer_disconnected) are now only connected when netfox
  NetworkEvents is NOT available, preventing duplicate player_connected/
  player_disconnected signal emissions.
- Fixed stop() to only disconnect ENet signals when they were actually
  connected (mirrors the conditional connection in start_server()).
- Fixed headless parse error in player_net_input.gd: replaced direct
  NetworkTime.before_tick_loop reference with Engine.get_singleton()
  call, avoiding unresolved type identifier in headless mode.
- netfox_bootstrap.gd added as minimal autoload placeholder.
- Dual-path architecture: netfox NetworkEvents when available (editor),
  ENet fallback when netfox unavailable (headless server).
- Broadcast RPCs (spawn, round state, scores) kept as-is since they
  work identically through Godot's MultiplayerAPI in both paths.
2026-07-02 17:39:06 -04:00
shawn db477b4c48 Fix simulation_server_stub Entity class conflict + ServerConfig load timing
- Renamed inner class Entity→StubEntity (Godot has native Entity class)
- Added await ServerConfig.config_loaded before reading map_list in server_main.gd
- Config loads via call_deferred, so _ready() must wait for signal
v0.1.0-playtest
2026-07-02 10:24:32 -04:00
shawn 4a5264c5b0 Fix headless class_name dependencies
- Replaced TeamData.Team type hints with int in all scripts
- Added explicit preloads for headless mode class resolution
- Created stub LagCompensation and DamageProcessor scripts
- Fixed PluginManager, SpawnManager, EconomyManager, BuyZone,
  RoundManager, BuyMenuHandler, BombObjective class_name references
- Updated server config to match ServerConfig.gd format

Gray screen root cause: server scripts failed to parse in headless
mode due to Godot 4 class_name loading order (Resource after Node),
leaving server_main.gd non-functional — accepted connections but
never spawned players.
2026-07-02 10:09:28 -04:00
shawn ad48f38ca5 feat: integrate ChaffGames FPS template as local player controller
Replaces the overhead box-mesh view with a full FPS character:

- mouse look, WASD movement, jump (Space), crouch (C), sprint (Shift), lean (Q/E)

- 6 weapons (LMB shoot, R reload, scroll switch, F melee, G drop)

- Crosshair HUD, ammo counter, sprint bar

- Client sends position to server at 20Hz for multiplayer visibility

- Server broadcasts positions to all peers

- Remote players shown as boxes (placeholder)

source: https://godotengine.org/asset-library/asset/2652 (MIT license)
2026-07-02 00:26:45 -04:00
shawn f0c95dcfd2 fix: create local player on client so WASD movement works
client_main.gd: when server spawns our player, create a player node with authority

- Camera follows local player from 3/4 overhead view

- player.gd WASD input sends position to server via RPC

- Server validates and broadcasts to all peers
2026-07-02 00:15:08 -04:00
shawn d060ac449d fix: suppress 3 benign startup warnings on Windows client
- Create missing server/plugins/ dir with .gdignore (stops PluginManager warning)

- Create config/default_server_config.cfg (stops ServerConfig error)

- Reorder light look_at after add_child (stops 'not in tree' warning)

- Switch rendering_method from opengl3 to forward_plus (RTX 2080 Vulkan works fine; gray screen was server-scene issue not OpenGL)
2026-07-02 00:05:27 -04:00
shawn 87060b0b71 fix: move sub_resource tags before nodes in test_range.tscn (export parse fix) 2026-07-02 00:02:25 -04:00
shawn 638e109d8b fix: client_main.tscn overrides server_host to 68.202.6.107 2026-07-01 22:21:29 -04:00
shawn 4c0e334575 fix: lazy load scenes in entry.gd (no preload of server in client mode) 2026-07-01 22:04:41 -04:00
shawn e270f34150 fix: client_main defaults to remote server (68.202.6.107) 2026-07-01 22:04:03 -04:00
shawn 20ca43f928 fix: add smart entry scene (client vs server via headless detection) 2026-07-01 21:44:14 -04:00
shawn aae57c63bd fix: TeamManager signal type hints — use int instead of TeamData.Team (export parse order issue) 2026-07-01 21:41:36 -04:00
shawn 0994a55486 chore: clean up duplicate .gdextension files (keep only gdextension/simulation.gdextension) 2026-07-01 21:38:46 -04:00
shawn 82216bfa64 fix: Windows client compile errors — get_world_3d on Node, array type mismatch, null plugin guard, maps format 2026-07-01 21:38:07 -04:00
shawn d5098c61e1 fix: switch to OpenGL 3 renderer for Windows compatibility (gray screen fix) 2026-07-01 21:16:26 -04:00
shawn 194aad8f83 t_p2_bomb: Bomb/defuse objective system for search & destroy rounds
Adds:
- bomb_objective.gd: server-authoritative bomb state machine (IDLE→PLANTED→EXPLODED/DEFUSED)
  - plant_bomb(player_id, pos) - T-side only, LIVE phase, inside bombsite
  - defuse_bomb(player_id) - CT-side only, near bomb, 5s timer
  - cancel_defuse(player_id) - if defuser moves or is killed
  - bomb_explode() - configurable radius damage (10m lethal, 15m half)
  - 40s bomb timer (configurable)
  - Full query API: is_bomb_planted(), get_bomb_position(), get_bomb_timer()
  - Signals: bomb_planted, bomb_defused, bomb_exploded, defuse_started, defuse_cancelled
  - Connected to RoundManager via GameServer for round-end outcomes

- bomb_carrier.gd: client-side bomb carrier UI
  - Bomb status/defuse progress UI updates
  - Direction indicator to planted bomb
  - "Hold E to defuse" prompt for CT near bomb
  - "Hold E to plant" prompt for T with bomb in bombsite

- test_range.tscn: BombsiteA (south-west, -20,0,-5) and BombsiteB (north-east, 15,0,20)
  - 8x4m Area3D zones with BoxShape3D collision
  - PlantPosition Marker3D children
  - Group 'bomb_sites' for server discovery

- game_server.gd: BombObjective integration in _ready()
  - Creates and wires BombObjective to RoundManager, TeamManager, DamageProcessor
  - Registers bomb sites from scene tree
  - Connects bomb_exploded/bomb_defused → RoundManager.end_round()
  - Connects round_ended → bomb.reset()
2026-07-01 20:39:17 -04:00
shawn 222dcaebb3 t_p4_anticheat: add basic server-side anti-cheat controller
- Rate limiting: flags players exceeding 130Hz input RPC rate
- Speed hacks: validates position deltas against max speed * 1.5
- Aimbot snap: flags look-direction changes >45° in one tick
- Suspicion level tracking (0.0-1.0) with decay over time
- Escalating thresholds: 0.3=warn(log), 0.6=kick(signal), 0.8=ban(signal, 1h temp)
- Configurable max speed via set_max_speed()
- Ban handler Callable for caller-defined disconnect logic
- Design: generous tolerances, near-zero false positives, Phase-4 basic hardening
2026-07-01 20:37:20 -04:00
shawn 0aa29d33e4 fix: GDExtension C++ build — fix enum bitwise cast, add .gdextension entry file 2026-07-01 20:34:15 -04:00