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>
This commit is contained in:
2026-07-02 20:55:20 -04:00
parent ce39b237c3
commit b0c83af092
4416 changed files with 57418 additions and 902676 deletions
+19
View File
@@ -0,0 +1,19 @@
extends RefCounted
signal on_partial_result(result: VestResult.Suite)
func run_script(_script: Script, _only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
# OVERRIDE
return VestResult.Suite.new()
func run_glob(_p_glob: String, _only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
# OVERRIDE
return VestResult.Suite.new()
func run_script_at(path: String, only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
var test_script := load(path)
if not test_script or not test_script is Script:
return null
return await run_script(test_script, only_mode)
@@ -0,0 +1 @@
uid://f1gd7s4rxrh1
+114
View File
@@ -0,0 +1,114 @@
extends "res://addons/vest/runner/vest-base-runner.gd"
class_name VestDaemonRunner
## Runs tests in a separate, background process
var _server: TCPServer
var _port: int
var _peer: StreamPeerTCP
var _is_debug_run := false
## Enable debug mode for the next run
func with_debug() -> VestDaemonRunner:
_is_debug_run = true
return self
## Run a test script
func run_script(script: Script, only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
var params := VestCLI.Params.new()
params.run_file = script.resource_path
params.only_mode = only_mode
return await _run_with_params(params)
## Run test scripts matching glob
## [br][br]
## See [method String.match]
func run_glob(glob: String, only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
var params := VestCLI.Params.new()
params.run_glob = glob
params.only_mode = only_mode
return await _run_with_params(params)
func _run_with_params(params: VestCLI.Params) -> VestResult.Suite:
var timeout := Vest.timeout(Vest.get_runner_timeout())
# Start host
if _start(-1) != OK:
push_error("Couldn't start vest host!")
return null
# Start process
params.host = "127.0.0.1"
params.port = _port
if not _is_debug_run:
VestCLI.run(params)
else:
_is_debug_run = false
VestCLI.debug(params)
# Wait for agent to connect
if await timeout.until(func(): return _server.is_connection_available()) != OK:
push_error("Agent didn't connect in time!")
return null
_peer = _server.take_connection()
var results = null
while true:
await Vest.sleep()
_peer.poll()
if _peer.get_status() != StreamPeerTCP.STATUS_CONNECTED:
break
if _peer.get_available_bytes() <= 0:
# No data, wait some more
continue
var message = _peer.get_var(true)
if message is Dictionary:
results = message
on_partial_result.emit(VestResult.Suite._from_wire(results))
_stop()
if results == null:
push_error("Test run failed!")
return null
elif results is Dictionary:
var suite_result = VestResult.Suite._from_wire(results)
return suite_result
else:
push_error("Unrecognized test result data! %s" % [results])
return null
func _start(port: int = -1):
# Start host
_server = TCPServer.new()
# Find random port for host
if port < 0:
for i in range(32):
port = randi_range(49152, 65535)
if _server.listen(port, "127.0.0.1") == OK:
break
else:
_server.listen(port, "127.0.0.1")
_port = port
if not _server.is_listening():
push_error("Failed to find available port!")
return ERR_CANT_CREATE
return OK
func _stop():
_peer.disconnect_from_host()
_server.stop()
_peer = null
_server = null
_port = -1
@@ -0,0 +1 @@
uid://btopw8r6n6fp1
+122
View File
@@ -0,0 +1,122 @@
extends "res://addons/vest/runner/vest-base-runner.gd"
class_name VestLocalRunner
var _result_buffer: VestResult.Suite
## Run a test script
func run_script(script: Script, only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
var _result_buffer = VestResult.Suite.new()
if not script:
return null
var test_instance = script.new()
if not test_instance is VestTest:
test_instance.free()
return null
var test := test_instance as VestTest
var suite = await test._get_suite()
var run_only := false
match only_mode:
Vest.__.ONLY_DISABLED: run_only = false
Vest.__.ONLY_AUTO: run_only = suite.has_only()
Vest.__.ONLY_ENABLED: run_only = true
await test._begin(test_instance)
_result_buffer = await _run_suite(_result_buffer, suite, test, run_only)
await test._finish(test)
test.free()
return _result_buffer
## Run test scripts matching glob
## [br][br]
## See [method String.match]
func run_glob(glob: String, only_mode: int = Vest.__.ONLY_DEFAULT) -> VestResult.Suite:
_result_buffer = VestResult.Suite.new()
_result_buffer.suite = VestDefs.Suite.new()
_result_buffer.suite.name = "Glob suite \"%s\"" % [glob]
# Gather suites
var suites := [] as Array[VestDefs.Suite]
var test_instances := [] as Array[VestTest]
var has_only = false
for test_file in Vest.glob(glob):
var test := _load_test(test_file)
if not test: continue
var subsuite := await test._get_suite()
test_instances.append(test)
suites.append(subsuite)
has_only = has_only or subsuite.has_only()
# Figure out only mode
var run_only := false
match only_mode:
Vest.__.ONLY_DISABLED: run_only = false
Vest.__.ONLY_AUTO: run_only = has_only
Vest.__.ONLY_ENABLED: run_only = true
# Run suites
for i in range(suites.size()):
var suite_result := VestResult.Suite.new()
_result_buffer.subsuites.append(suite_result)
var response := await _run_suite(suite_result, suites[i], test_instances[i], run_only)
if not response:
_result_buffer.subsuites.erase(suite_result)
# Cleanup
for test in test_instances:
test.free()
return _result_buffer
func _load_test(path: String) -> VestTest:
var script := load(path)
if not script or not script is Script:
return null
var test_instance = (script as Script).new()
if not test_instance is VestTest:
return null
return test_instance as VestTest
func _run_case(case: VestDefs.Case, test_instance: VestTest, run_only: bool, is_parent_only: bool = false) -> VestResult.Case:
if run_only and not case.is_only and not is_parent_only:
return null
await test_instance._begin(case)
await case.callback.call()
await test_instance._finish(case)
on_partial_result.emit(_result_buffer)
return test_instance._get_result()
func _run_suite(result: VestResult.Suite, suite: VestDefs.Suite, test_instance: VestTest, run_only: bool, is_parent_only: bool = false) -> VestResult.Suite:
if run_only and not suite.has_only() and not is_parent_only:
return null
result.suite = suite
await test_instance._begin(suite)
for subsuite in suite.suites:
var suite_result := VestResult.Suite.new()
suite_result = await _run_suite(suite_result, subsuite, test_instance, run_only, is_parent_only or suite.is_only)
if suite_result != null:
result.subsuites.append(suite_result)
for case in suite.cases:
var case_result := await _run_case(case, test_instance, run_only, is_parent_only or suite.is_only)
if case_result != null:
result.cases.append(case_result)
await test_instance._finish(suite)
return result
@@ -0,0 +1 @@
uid://bteqiowekiut