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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user