b0c83af092
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>
137 lines
4.4 KiB
GDScript
137 lines
4.4 KiB
GDScript
extends Object
|
|
class_name VestMixins
|
|
|
|
## Manages mixins for [VestTest].
|
|
##
|
|
## Instead of having to implement all the functionality in one huge class,
|
|
## the functionality can be separated into mixins.
|
|
## [br][br]
|
|
## Mixins are classes whose functionality is combined into a single class, to
|
|
## produce the [VestTest] base class. This is done by generating scripts that
|
|
## Godot can then load.
|
|
## [br][br]
|
|
## When working with custom mixins, [b]make sure to refresh[/b] when a change
|
|
## is applied!
|
|
|
|
## List all active mixins.
|
|
static func list() -> Array[Script]:
|
|
var result: Array[Script] = []
|
|
result.assign((VestTest.new()).__get_vest_mixins())
|
|
return result
|
|
|
|
## Add a custom script to the list of mixins.
|
|
## [br][br]
|
|
## Make sure to call [method refresh], otherwise the generated classes are not
|
|
## updated.
|
|
static func add(mixin: Script):
|
|
var active_mixins := list()
|
|
if not active_mixins.has(mixin):
|
|
active_mixins.append(mixin)
|
|
refresh(active_mixins)
|
|
|
|
## Remove a custom script from the list of mixins.
|
|
## [br][br]
|
|
## Make sure to call [method refresh], otherwise the generated classes are not
|
|
## updated.
|
|
static func remove(mixin: Script):
|
|
var active_mixins := list()
|
|
if active_mixins.has(mixin):
|
|
active_mixins.erase(mixin)
|
|
refresh(active_mixins)
|
|
|
|
## Refresh the generated classes, making sure that all mixins used are up to
|
|
## date.
|
|
static func refresh(mixins: Array[Script] = []):
|
|
if mixins.is_empty():
|
|
mixins = list()
|
|
|
|
# Generate mixin chain
|
|
var mixin_chain: Array[Script] = []
|
|
mixin_chain.append(_get_test_base())
|
|
mixin_chain.append_array(_get_builtin_mixins())
|
|
|
|
var active_mixins: Array[Script] = []
|
|
|
|
for mixin_script in mixins:
|
|
if not mixin_script:
|
|
# Not script?
|
|
continue
|
|
|
|
if mixin_chain.has(mixin_script):
|
|
# Don't include the same mixin twice
|
|
continue
|
|
|
|
mixin_chain.append(mixin_script)
|
|
active_mixins.append(mixin_script)
|
|
|
|
mixin_chain.append(VestTest)
|
|
|
|
# Generate scripts
|
|
_clean_mixin_directory()
|
|
DirAccess.make_dir_recursive_absolute(_get_mixin_directory())
|
|
var extends_pattern := RegEx.create_from_string("^extends.*")
|
|
|
|
for i in range(1, mixin_chain.size()):
|
|
var parent_script := mixin_chain[i - 1]
|
|
var target_script := mixin_chain[i]
|
|
|
|
var parent_path := parent_script.resource_path
|
|
var target_path := target_script.resource_path
|
|
|
|
if i != 1:
|
|
parent_path = _get_generated_mixin_path(parent_script, i - 1)
|
|
if i != mixin_chain.size() - 1:
|
|
target_path = _get_generated_mixin_path(target_script, i)
|
|
|
|
# Generate source
|
|
var target_source := target_script.source_code
|
|
var script_header := (
|
|
"# This file is generated by Vest!\n" +
|
|
"# Do not modify!\n" +
|
|
"# source: %s\n" % [target_script.resource_path] +
|
|
"extends \"%s\"\n\n" % [parent_path])
|
|
|
|
target_source = extends_pattern.sub(target_source, "", true)
|
|
if target_script != VestTest:
|
|
target_source = script_header + target_source
|
|
else:
|
|
target_source = script_header
|
|
target_source += "class_name VestTest\n\n"
|
|
|
|
var mixin_fragments = active_mixins\
|
|
.map(func(it): return it.resource_path)\
|
|
.map(func(it): return "preload(\"%s\")" % it)
|
|
|
|
mixin_fragments = ", ".join(mixin_fragments)
|
|
target_source += "func __get_vest_mixins() -> Array:\n\treturn [%s]" % [mixin_fragments]
|
|
|
|
var target_file := FileAccess.open(target_path, FileAccess.WRITE)
|
|
target_file.store_string(target_source)
|
|
target_file.close()
|
|
|
|
static func _get_generated_mixin_name(script: Script, idx: int) -> String:
|
|
return "%d-%x.gd" % [idx, hash(script.resource_path.get_file())]
|
|
|
|
static func _get_generated_mixin_path(script: Script, idx: int) -> String:
|
|
return _get_mixin_directory() + _get_generated_mixin_name(script, idx)
|
|
|
|
static func _get_builtin_mixins() -> Array[Script]:
|
|
return [
|
|
preload("res://addons/vest/test/mixins/gather-suite-mixin.gd"),
|
|
preload("res://addons/vest/test/mixins/expect-mixin.gd"),
|
|
preload("res://addons/vest/test/mixins/assert-that-mixin.gd"),
|
|
preload("res://addons/vest/test/mixins/mock-mixin.gd"),
|
|
preload("res://addons/vest/test/mixins/capture-signal-mixin.gd"),
|
|
preload("res://addons/vest/test/mixins/logging-mixin.gd")
|
|
]
|
|
|
|
static func _get_mixin_directory() -> String:
|
|
return "res://addons/vest/_generated-mixins/"
|
|
|
|
static func _clean_mixin_directory():
|
|
for file in DirAccess.get_files_at(_get_mixin_directory()):
|
|
DirAccess.remove_absolute(_get_mixin_directory() + file)
|
|
|
|
static func _get_test_base() -> Script:
|
|
return preload("res://addons/vest/test/vest-test-base.gd") as Script
|