Commit Graph

41 Commits

Author SHA1 Message Date
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
shawn 6a08487c4c t_p2_buy: add buy menu and economy system
Creates the full buy/economy subsystem for a tactical FPS:

- EconomyManager (server/scripts/economy/economy_manager.gd): per-player
  money tracking with starting 00, kill/round/objective rewards, spending
  validation, escalating loss bonuses, and money_changed signal.

- BuyMenuHandler (server/scripts/economy/buy_menu_handler.gd): server-side
  RPC validation of purchase requests — checks weapon validity, buy-zone
  membership (scans BuyZone nodes in scene tree), affordability, then
  deducts money and grants weapon via WeaponServer.give_weapon().

- BuyMenu (client/characters/weapon/buy_menu.gd): client-side Control UI
  with styled panel, money display, weapon grid (name/cost/stats), numeric
  key (1-4) and mouse-click purchase, server-driven affordability, and
  auto-close after purchase.

- GameServer integration: creates EconomyManager + BuyMenuHandler in
  _ready(), registers players for economy on spawn, awards kill rewards
  via DamageProcessor.player_killed signal, and unregisters on despawn.

Economy rules: win=+,250, loss=,900 (+00/streak, cap ,900),
kill=+00, bomb_plant/defuse=+00. Weapon costs: pistol=00,
smg=,200, rifle=,700, shotgun=,900.
2026-07-01 20:31:25 -04:00
shawn f20d532add t_p1_round: Add round/match lifecycle system (RoundManager)
- New server/scripts/round/round_manager.gd with:
  - RoundPhase enum (WARMUP, PREP, LIVE, POST)
  - Round life cycle: warmup -> prep (15s) -> live (105s) -> post (8s)
  - Team elimination detection using entity->peer->team mappings
  - Time-expired round ending (default: CT wins)
  - Economy hooks: win money (250), loss money (900 escalating to 900), kill bonus (00)
  - All requested signals: round_phase_changed, round_started, round_ended, match_point, warmup_ended, round_economy_data

- Updated GameServer:
  - Creates and wires RoundManager in _ready()
  - Connects DamageProcessor.player_killed -> round tracking + elimination detection
  - Added peer_to_entity mapping for backwards entity lookup
  - Added RCON command handler (_on_rcon_command) for start_match/end_round

- Updated RCON command handler:
  - Added start_match and end_round to dispatch list and help text
2026-07-01 20:30:01 -04:00
shawn 705b068ed2 t_p1_hitscan: Add lag-compensated hitscan weapon system
NEW: server/scripts/combat/lag_compensation.gd
  - 128-entry ring buffer of player positions per server tick
  - rewind_and_raycast(tick, origin, direction, range, exclude):
    saves current positions, rewinds to tick-time positions,
    performs PhysicsDirectSpaceState3D.intersect_ray(), restores
  - Falls back to normal raycast if history missing for tick
  - shot_processed signal

NEW: scripts/combat/damage_processor.gd
  - Processes WeaponServer hit results: applies damage, tracks kills
  - Optional distance-based damage falloff
  - player_damaged / player_killed signals
  - Health and kill-count queries

MODIFY: server/scripts/weapons/weapon_server.gd
  - fire() now takes tick parameter: fire(tick, player_id, ...)
  - _perform_hitscan() uses LagCompensation.rewind_and_raycast()
    when lag_compensation reference is set and tick >= 0
  - Non-compensated fallback path preserved

MODIFY: server/scripts/game_server.gd
  - Adds _current_tick counter, incremented each simulation tick
  - Creates WeaponServer + LagCompensation + DamageProcessor as children
  - record_tick() called before each tick's simulation
  - register/unregister_player_node() for player lifecycle
  - _on_player_killed() relays kill events via player_damaged signal

MODIFY: scripts/network/server_main.gd
  - _spawn_player() registers node with GameServer.register_player_node()
  - _despawn_player() unregisters via unregister_player_node()
2026-07-01 20:26:18 -04:00
shawn 3465922be4 t_p6_browser: add workshop map browser with voting (3 files)
- workshop_browser.gd: scans server maps dir for .pck/.tscn files
- map_browser_rpc.gd: client-server RPC bridge for map list/change
- map_vote.gd: simple >50% majority vote with 30s timeout

File scope:
  server/scripts/browser/workshop_browser.gd (NEW)
  scripts/network/map_browser_rpc.gd (NEW)
  server/scripts/browser/map_vote.gd (NEW)
2026-07-01 20:24:23 -04:00
shawn 46ff83325f t_p2: Add team, spawn, and buy-zone system
- team_data.gd: Team enum (SPECTATOR/CT/Terrorist), constants for names,
  colors, starting money, and spawn groups; TeamData resource class
- team_manager.gd: Player-to-team assignment, auto-balancing, score
  tracking; round-independent (persists across rounds)
- spawn_manager.gd: Scans scene for Marker3D nodes in spawn_points_ct
  and spawn_points_t groups; selects valid spawns (farthest from enemies
  with proximity check, fallback to first available)
- buy_zone.gd: Area3D-based trigger zone with team filtering, player
  enter/exit tracking and signals
- test_range.tscn: Added 2 CT spawn markers and 2 T spawn markers with
  appropriate groups
2026-07-01 20:24:16 -04:00
shawn f6d69545c9 feat: implement client-side prediction and reconciliation system
Add client-side prediction (t_p1_pred) with:

- scripts/network/snapshot.gd — lightweight snapshot resource with
  to_dict/from_dict serialization for RPC. Stores position (Vector3),
  rotation (Quaternion), velocity (Vector3), grounded (bool).

- scripts/network/client_prediction.gd — prediction/reconciliation
  controller. 64-entry ring buffer of local snapshots, sends inputs to
  server each physics tick (128Hz, ENet channel 0), detects misprediction
  on server state arrival, rewinds and re-applies unconfirmed inputs.
  Also supports remote player interpolation.

- scripts/network/network_manager.gd — new RPC endpoints for client
  prediction: send_client_input (client->server, ch 0) and
  send_server_state (server->client, ch 1). New signals for routing.

- client/characters/character/fps_character_controller.gd — prediction
  hooks in _physics_process: on_before_tick() captures pre-input
  snapshot, on_after_tick() sends input to server. Client prediction
  path uses local movement (instant feedback) instead of reading from
  SimulationServer entity.

Architecture:
  Each tick: client applies input → predicts new state locally
  → sends input to server → server returns authoritative state
  → client compares and reconciles if mismatch.
2026-07-01 20:21:16 -04:00
shawn 2452aba0d7 feat: implement weapon set system (t_p2_weapons)
- WeaponData resource class with configurable weapon properties and
  pre-configured constants for rifle, pistol, shotgun, and SMG
- WeaponDefinitions singleton/static registry with WEAPONS dictionary
- WeaponServer node for server-authoritative weapon logic including
  fire rate cooldowns, ammo tracking, reload state machine, and
  multi-pellet hit-scan raycasting
- Extended WeaponManager with weapon inventory array, weapon switching,
  per-weapon state persistence, fire_animation_triggered signal
2026-07-01 20:16:22 -04:00
shawn 3c3251fa7a feat: add t_p1_greybox — greybox test map scene
Creates test_range.tscn under client/assets/maps/test_range/ as a simple
open-area test map for validating movement, shooting, and networking.

Layout:
- 80×80 open area with grey floor (CSGBox3D, 12 tris)
- Low platform (center, 1 unit high, gold)
- Medium platform (east, 2 units high, gold)
- High platform (north-west, 3 units high, red)
- Ramp (south, tilted ~20°, leads ground to low platform top)
- Enclosure/room (east, 12×12 interior, 4-unit walls, south doorway)
- SpawnPoint (Marker3D) with group 'spawn_points'
- DirectionalLight3D (sun) + WorldEnvironment
- All geometry uses Solid-color StandardMaterial3D placeholders
- Collision enabled on all CSGBox3D shapes
- ~132 tris total (well under 500 budget)
2026-07-01 20:15:34 -04:00
shawn d02b112d99 Phase 7: test server deployment + Windows export
- Fix: export_presets.cfg — platform='Windows Desktop' (correct name)
- Fix: server_main.gd — formatting bug on lag-comp string
- Fix: game_server.gd — auto-detect GDExtension, fall back to GDScript stub
- Add: server/scripts/simulation_server_stub.gd — lightweight SimulationServer in GDScript
- Add: docs/playtest-guide.md — connection instructions, control bindings, server commands
- Add: systemd user service — tactical-shooter-server (enabled, running)
- Add: server config at ~/tactical-shooter-server/server_config.cfg
- Build: Windows 109MB PE32+ client (build/tactical-shooter-windows-x86_64/)
- Build: Linux server binary (78MB) — running on oplabs:34197
- Temporarily disabled GDExtension (needs C++ build fix in entity.cpp enum casting)
2026-07-01 20:02:05 -04:00
shawn 2582cb1b0d Phase 7: Windows export preset fix + code fixes
- Fix: export_presets.cfg — platform='Windows Desktop' (not 'Windows'), Windows as [preset.0]
- Fix: plugin_manager.gd — removed class_name (autoload conflict), fixed multiline % formatting
- Disable GDExtension temporarily for clean export
- Add build/ to .gitignore (binary artifacts)
- Build artifacts: tactical-shooter.exe (109MB Windows PE32+), windows.zip, server binary (78MB)
2026-07-01 19:47:12 -04:00
shawn 9ea98aa7b8 Phase 7: Windows client export, preset fix, code fixes
- Fix: export_presets.cfg — platform='Windows Desktop' (not 'Windows'), Windows as [preset.0]
- Fix: plugin_manager.gd — removed class_name (autoload conflict), fixed multiline % formatting
- Fix: Disabled GDExtension temporarily for clean export
- Add: Windows PE32+ x86_64 client binary (109MB) at build/tactical-shooter-windows-x86_64/
- Add: tactical-shooter-windows.zip (portable zip package)
- Build: Linux server binary (78MB) rebuilt
2026-07-01 19:47:12 -04:00
shawn e385eae0f5 feat: performance budget profiling setup
- docs/performance-budget.md: 60fps/2GB VRAM budget with CPU, GPU,
  memory, and draw-call targets (P95<16.6ms, P99<50ms)
- scripts/profiling/: SceneTree + Node profilers, test scenes
- scripts/generate_occluders.gd: auto-generate OccluderInstance3D
  from CSG wall pieces (128^3 voxel occlusion culling)
- scripts/convert_csg_to_mesh.gd: CSG->StaticMesh baker with LOD
  slots (LOD1@15m, LOD2@30m)
- project.godot: occlusion culling + LOD settings enabled
- modular scene UV2 data from lightmapping pass
- rcon_command_handler.gd conflict resolved (kept upstream plugin cmd)
- Fixed profiler_node.gd warmup frame bug (60 frames, not 3)
- Fixed convert_csg_to_mesh.gd LOD API (add_lod + distance)
2026-07-01 19:01:03 -04:00
shawn 34507f9043 docs: community mapmaking documentation (7-file SDK guide)
- docs/mapmaking/00-index.md — SDK overview with workflow diagram
- docs/mapmaking/01-getting-started.md — template setup & first map
- docs/mapmaking/02-building-geometry.md — CSG guide & prefab reference
- docs/mapmaking/03-lighting-and-env.md — LightmapGI baking guide
- docs/mapmaking/04-validation.md — validator CLI & CI/CD usage
- docs/mapmaking/05-packaging-and-shipping.md — .pck pipeline
- docs/mapmaking/06-faq-and-troubleshooting.md — 30+ common issues
- README.md — add mapmaking SDK link to features list
2026-07-01 18:47:06 -04:00
shawn 159c554a86 t_p6_api: build plugin scripting system
- Add PluginBase (plugin_base.gd) — abstract base class with 12 virtual hooks
- Add PluginManifest (plugin_manifest.gd) — custom Resource for plugin metadata
- Add PluginManager (plugin_manager.gd) — autoload singleton: directory scan,
  hook dispatch, lifecycle (load/unload/reload/rescan), cvar integration
- Add hello_world example plugin with all hooks demonstrating usage
- Register PluginManager autoload in project.godot
- Extend rcon_command_handler.gd with 'plugin' subcommand (list/load/unload/
  reload/info/rescan) delegating to PluginManager
2026-07-01 18:36:23 -04:00
shawn ffa72a8f24 t_p5_validator: add 5 Godot 4 map validator scripts
- validate_map.gd — scene structure validator (CSG combiner root, spawn groups,
  bomb sites, buy zones, map bounds, LightmapGI config, lighting setup)
- validate_polycount.gd — CSG triangle budget checker
  (<50K faces, <5K per node, <200 CSG nodes)
- validate_textures.gd — texture size ≤1K, mipmaps, UV2 checker
- validate_lights.gd — dynamic lights ≤4, bake mode validator
- bake_lightmaps.gd — LightmapGI config checker
  (quality, bounces, texel_scale, interior, denoiser)

All scripts: @tool SceneTree, accept scene path via -- separator,
exit 0=pass / 1=fail / 2=scene-not-found. 443-610 lines each.
2026-07-01 18:35:52 -04:00
shawn 589b90d886 fix: FPS character controller review fixes
- Camera: Make view bob additive to crouch eye height (was overwriting position.y)
- Camera: Sustain sprint FOV kick while sprinting (was recovering immediately)
- Camera: Remove unused _was_sprinting variable
- Controller: Use just_pressed for jump (was sending every frame while held)
- Controller: Direct input dict assignment instead of merge() to avoid alloc
- Controller: Add clearer comments on server-authoritative readback mode
2026-07-01 18:35:16 -04:00
shawn e9dc05983c Save workspace artifacts: character-controller, gdextension scaffold, network scripts, map-pipeline, server config
Includes code from task workspaces that was never pushed:
- client/characters/ — fps_character_controller.gd (400 lines), fps_camera.gd, input_handler.gd
- gdextension/simulation/ — C++ GDExtension scaffold: entity, movement, hit detection, simulation server, state serializer, bitstream (14 files)
- scripts/network/ — ENet-based network_manager.gd, server/client_main.gd, player.gd
- scripts/map_packaging/ — PCK pipeline: pack_map.gd, map_downloader.gd, map_registry_server.py, README
- scripts/config/ — server_config.gd (480 lines)
- scenes/ — client_main, server_main, player, test_range
- project.godot, export_presets.cfg
2026-07-01 18:30:44 -04:00
shawn 2cf57a989f t_p4_rcon: RCON admin console — TCP listener + command handler
Implementation:
- server/scripts/rcon_server.gd — TCPServer-based listener, auth state
  machine (3-strike penalty), per-frame I/O polling, StreamPeerTCP
  per-connection management, IP-based auth timeout
- server/scripts/rcon_command_handler.gd — 14-command dispatch table,
  signal-based dispatch for game-affecting commands (changelevel, kick,
  ban, say, players, exec), inline handlers for help/echo/status/quit and
  cvar operations via optional CvarRegistry singleton (t_p4_config)
- server/data/rcon_password.cfg — default password file (gitignored)
- .gitignore — exclude password file from version control

Protocol: Source-RCON-inspired lightweight TCP, newline-delimited commands,
END-terminated multi-line responses. First message = password auth.
3 failed auth attempts → 5s reconnect penalty.

CvarRegistry integration: auto-detects /root/CvarRegistry singleton on
_ready() and reads rcon_enabled, rcon_port, rcon_password if present.
2026-07-01 00:31:03 -04:00
shawn 16e062c739 build: baked lighting pass on kit_demo test map
Restructured kit_demo.tscn from linear demo to enclosed 5.12x5.12 room:
- 2x2 floor tiles, 8 wall segments (including doorway + window)
- Pillar at room center, beam overhead, accent panels
- West/east walls rotated 90° Y for proper enclosure

Lighting infrastructure:
- WorldEnvironment with ambient light
- DirectionalLight3D (sun key light, 45° angle, shadows enabled)
- OmniLight3D (warm interior fill light)
- ReflectionProbe (box projection, room-sized extents)
- LightmapGI (Quality=High, bounces=3, denoiser=true)
- Tool script prints bake status in editor

Scripts:
- bake_lighting.gd: validates LightmapGI config from CLI
- validate_scene.gd: full scene validation (17 checks, all pass)

Note: Godot 4.7 removed LightmapGI.bake() from runtime API.
Baking must be done in the editor: select LightmapGI node > Bake Lightmap.
2026-07-01 00:28:55 -04:00
shawn aa0b80b570 Phase 4: server-hardening architecture doc
- Server hosting architecture overview (4-component diagram)
- RCON admin console spec (TCP protocol, commands, auth)
- Server config system spec (cfg format, cvars, loading pipeline)
- Server browser API spec (master server REST API, heartbeat, client UI)
- Anti-cheat basics spec (movement, fire rate, input validation)
- Config loading pipeline, anti-cheat pipeline diagrams
- Full cvar table for Phase 4

Part of Phase 4 orchestration (t_29fcfd24)
2026-07-01 00:19:43 -04:00
shawn d631ff784a build: baked lighting pass on kit_demo test map
- Restructured kit_demo.tscn from linear demo to enclosed 5.12x5.12 room
  with walls, floor tiles, pillar, beam, doorway, window
- Added WorldEnvironment with ProceduralSky for ambient lighting
- Added DirectionalLight3D (sun key light, 45° angle, shadows enabled)
- Added OmniLight3D (warm interior fill light)
- Added ReflectionProbe for interior specular reflections
  (box projection, room-sized extents)
- Added LightmapGI with balanced quality settings
  (bounces=3, texel_scale=1.0, max_texture_size=2048, denoiser=true)
- Added tool script (kit_demo.gd) that prints bake status in editor
- Added bake_lighting.gd CLI bake script (requires GPU-enabled instance)
- Updated project.godot with reflection atlas and shadow map quality settings

Headless baking note: Godot's standard editor build requires a GPU/display
for LightmapGI.bake(). Open the scene in the Godot editor and click 'Bake
Lightmap' on the LightmapGI node to generate the baked lightmap data.
2026-07-01 00:10:19 -04:00
shawn 001ba3952e docs: Phase 3 architecture — visuals, lighting, profiling pipeline 2026-06-30 23:35:30 -04:00
shawn d919401012 Add full project plan 2026-06-30 21:00:57 -04:00
shawn eb4554f1e7 Initial commit: project plan, directory structure, docs 2026-06-30 21:00:48 -04:00
shawn 4f2b3a66b4 Initial commit 2026-07-01 01:00:29 +00:00