e7299b17e9
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)
204 lines
11 KiB
Markdown
204 lines
11 KiB
Markdown
# Phase 7: Stack Upgrade — netfox + godot-jolt Migration Plan
|
|
|
|
## Overview
|
|
|
|
Migrate from raw **ENetMultiplayerPeer** to **netfox** (foxssake/netfox, 1020⭐ MIT)
|
|
for rollback netcode, client prediction, and lag compensation. Add **godot-jolt**
|
|
(godot-jolt/godot-jolt, 2535⭐ MIT) for deterministic 128Hz physics.
|
|
|
|
**Reference architecture:** [naxIO/netfox-cs-sample](https://github.com/naxIO/netfox-cs-sample)
|
|
— CS 1.6 clone using netfox rollback patterns (teams, economy, bomb, 6 weapons).
|
|
|
|
---
|
|
|
|
## Current Architecture (Pre-Migration)
|
|
|
|
```
|
|
┌───────────────────────────────────────────────────┐
|
|
│ project.godot │
|
|
│ Autoloads: NetworkManager, ServerConfig, │
|
|
│ RoundManager, PluginManager │
|
|
│ Physics: 128Hz (Godot built-in) │
|
|
│ Rendering: Vulkan Forward+ │
|
|
│ Main Scene: server_main.tscn │
|
|
└─────────────────────┬─────────────────────────────┘
|
|
│
|
|
┌─────────────┴──────────────┐
|
|
▼ ▼
|
|
┌─────────────────┐ ┌──────────────────────────┐
|
|
│ network_manager │ │ SimulationServer │
|
|
│ .gd (ENet) │ │ (GDExtension C++) │
|
|
│ │ │ │
|
|
│ - ENetMultiplayer│ │ - entity spawning │
|
|
│ - 3 channels │ │ - apply_input() │
|
|
│ - RPC broadcasts │ │ - fire_weapon() │
|
|
│ - signals: │ │ - get_entity() │
|
|
│ player_* │ └──────────┬────────────────┘
|
|
│ round_* │ │
|
|
│ score_* │ ┌──────────▼────────────────┐
|
|
└─────────────────┘ │ fps_character_controller │
|
|
│ .gd (CharacterBody3D) │
|
|
┌─────────────────┐ │ │
|
|
│ round_manager │ │ - Input → SimulationServer│
|
|
│ .gd (state │ │ - move_local() fallback │
|
|
│ machine) │ │ - crouch, sprint, jump │
|
|
│ │ └────────────────────────────┘
|
|
│ - signals: │
|
|
│ round_*,score │ ┌──────────────────────────┐
|
|
│ - _process tick │ │ Player (Node3D) │
|
|
└─────────────────┘ │ - basic BoxMesh │
|
|
│ - movement_speed param │
|
|
└──────────────────────────┘
|
|
```
|
|
|
|
**Key issue:** ENet has no rollback, no client prediction, no lag compensation.
|
|
Players on slower connections will feel inconsistent hit registration.
|
|
|
|
---
|
|
|
|
## Target Architecture (Post-Migration)
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────┐
|
|
│ project.godot │
|
|
│ Autoloads: (same, NetworkManager rewired) │
|
|
│ Physics: Jolt @ 128Hz (godot-jolt GDExtension) │
|
|
│ Rendering: Vulkan Forward+ │
|
|
│ Addons: netfox, netfox.noray, netfox.extras │
|
|
└─────────────────────┬──────────────────────────────┘
|
|
│
|
|
┌─────────────┴──────────────┐
|
|
▼ ▼
|
|
┌──────────────────────┐ ┌──────────────────────────┐
|
|
│ netfox core │ │ netfox.noray │
|
|
│ (NetworkEvents, │ │ (NAT punchthrough) │
|
|
│ RollbackSynch., │ └──────────────────────────┘
|
|
│ TickInterpolator) │
|
|
└──────────┬───────────┘ ┌──────────────────────────┐
|
|
│ │ netfox.extras │
|
|
▼ │ (BaseNetInput, │
|
|
┌──────────────────────┐ │ RewindableStateMachine)│
|
|
│ NetworkManager.gd │ └──────────────────────────┘
|
|
│ (wrapper over netfox │
|
|
│ NetworkEvents + │ ┌──────────────────────────┐
|
|
│ MultiplayerSynch.) │ │ godot-jolt │
|
|
└──────────┬───────────┘ │ (deterministic physics) │
|
|
│ └──────────────────────────┘
|
|
▼
|
|
┌────────────────────────────────────────────────────┐
|
|
│ RollbackSynchronizer (player state) │
|
|
│ - _rollback_tick() → deterministic state sync │
|
|
│ - TickInterpolator → smooth visuals │
|
|
│ - Client prediction: apply input locally, │
|
|
│ reconcile from server snapshot │
|
|
└────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌────────────────────────────────────────────────────┐
|
|
│ RewindableAction (hitscan weapons) │
|
|
│ - Server-authoritative hit detection │
|
|
│ - Server rewinds physics to match client timing │
|
|
│ - Per-limb damage: head/chest/waist/legs │
|
|
└────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Migration Phases (Task Breakdown)
|
|
|
|
### P7.1 Research — netfox migration plan ✅ [THIS DOCUMENT]
|
|
|
|
### P7.2 Install — netfox addon
|
|
1. Download latest release from GitHub
|
|
2. Extract addons/netfox/, addons/netfox.noray/, addons/netfox.extras/, addons/netfox.internals/
|
|
3. Enable in Project Settings → Plugins
|
|
4. Verify `godot --headless --check-only` compiles
|
|
|
|
### P7.3 Install — godot-jolt physics
|
|
1. Download from releases or Asset Library
|
|
2. Copy addons/godot-jolt/ into project
|
|
3. Enable plugin, configure physics → 128Hz
|
|
4. Verify headless compilation
|
|
|
|
### P7.4 Port — NetworkManager.gd
|
|
**Source:** `scripts/network/network_manager.gd` (214 lines, ENet wrapper)
|
|
**Changes:**
|
|
- Replace `ENetMultiplayerPeer` → netfox `NetworkEvents`
|
|
- `start_server()` → use netfox's NetworkEvents server flow
|
|
- `join_server()` → use netfox's NetworkEvents client flow
|
|
- Player replication signals → netfox `MultiplayerSynchronizer` or `RollbackSynchronizer`
|
|
- Round state RPCs (`broadcast_round_*`) → netfox events
|
|
- Remove channel system (netfox handles prioritisation internally)
|
|
|
|
**Equivalent vs New:**
|
|
|
|
| Current ENet | netfox Equivalent |
|
|
|---|---|
|
|
| ENetMultiplayerPeer | NetworkEvents (connect/disconnect) |
|
|
| @rpc("authority", "call_local", "reliable") | MultiplayerSynchronizer / RollbackSynchronizer |
|
|
| broadcast_spawn_player RPC | NetworkEvents + spawn hook |
|
|
| broadcast_round_start RPC | NetworkEvents event |
|
|
| 3 channels (input/events/telemetry) | Automatic (netfox manages ordering) |
|
|
| _process polling | TickInterpolator / _rollback_tick() |
|
|
|
|
### P7.5 Build — Client Prediction + Rollback
|
|
**Key netfox patterns:**
|
|
- `RollbackSynchronizer` with `_rollback_tick()` for deterministic state sync
|
|
- `BaseNetInput` with `_gather()` for input collection
|
|
- `TickInterpolator` for smooth visual interpolation between ticks
|
|
- Client-side prediction: apply input immediately, reconcile when server snapshot arrives
|
|
|
|
### P7.6 Build — Rollback Hitscan + Lag Compensation
|
|
**Key netfox patterns:**
|
|
- `RewindableAction` for rollback-safe weapon firing
|
|
- Server rewinds entity positions to match client's input timestamp
|
|
- Hit detection inside rollback loop
|
|
- Per-limb damage (head 2x, chest 1.0x, waist 0.75x, legs 0.5x)
|
|
|
|
### P7.7 Port — RoundManager to netfox
|
|
**Source:** `server/scripts/round_manager.gd` (647 lines)
|
|
**Changes:**
|
|
- Round state signals (`round_started`, `round_ended`, etc.) → netfox events
|
|
- `player_died` etc. → netfox replicated state or RPCs
|
|
- `get_round_state_snapshot()` → netfox synchronized property
|
|
|
|
### P7.8 Port — FPS Controller to BaseNetInput
|
|
**Source:** `client/characters/character/fps_character_controller.gd` (401 lines)
|
|
**Changes:**
|
|
- Replace manual `_input_dict` → `BaseNetInput` subclass
|
|
- Use `_gather()` to collect input per tick
|
|
- Movement logic becomes server-authoritative (no more `move_local` fallback except singleplayer)
|
|
- Keep mouse look, crouch transition, sprint toggle — adapt for netfox tick
|
|
|
|
### P7.9 Test — Headless Export + Deployment
|
|
- `godot --headless --export-debug "Linux/X11" build/server/tactical-shooter.x86_64`
|
|
- Server starts clean, clients connect, rollback works across LAN
|
|
- Push to Gitea, update systemd service, verify on server
|
|
|
|
---
|
|
|
|
## Reference Files
|
|
|
|
| File | Lines | Key Role |
|
|
|---|---|---|
|
|
| `scripts/network/network_manager.gd` | 214 | ENet transport wrapper, RPC broadcasts |
|
|
| `scripts/network/player.gd` | ~60 | Basic player node |
|
|
| `scripts/network/server_main.gd` | ~150 | Server entry point |
|
|
| `scripts/network/client_main.gd` | ~120 | Client entry point |
|
|
| `client/characters/character/fps_character_controller.gd` | 401 | FPS movement + input to SimulationServer |
|
|
| `client/characters/character/fps_camera.gd` | ~80 | Camera look |
|
|
| `server/scripts/round_manager.gd` | 647 | Round state machine |
|
|
| `server/scripts/plugin_api/plugin_manager.gd` | 573 | Plugin system |
|
|
| `scenes/server/server_main.tscn` | 14 | Server scene |
|
|
| `scenes/client/client_main.tscn` | 14 | Client scene |
|
|
| `scenes/player.tscn` | 15 | Player prefab |
|
|
| `project.godot` | 33 | Autoloads, physics settings |
|
|
|
|
## Resources
|
|
|
|
- [netfox docs](https://foxssake.github.io/netfox/)
|
|
- [netfox GitHub](https://github.com/foxssake/netfox)
|
|
- [naxIO/netfox-cs-sample — CS 1.6 reference](https://github.com/naxIO/netfox-cs-sample)
|
|
- [godot-jolt GitHub](https://github.com/godot-jolt/godot-jolt)
|
|
- [VANTIX tactical shooter reference (C#, architecture only)](https://github.com/justin-bobr/vantix)
|