Files
tactical-shooter/addons/netfox/network-performance.gd
T
shawn b0c83af092 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>
2026-07-02 20:55:20 -04:00

182 lines
6.7 KiB
GDScript

extends Node
class_name _NetworkPerformance
const NETWORK_LOOP_DURATION_MONITOR: StringName = &"netfox/Network loop duration (ms)"
const ROLLBACK_LOOP_DURATION_MONITOR: StringName = &"netfox/Rollback loop duration (ms)"
const NETWORK_TICKS_MONITOR: StringName = &"netfox/Network ticks simulated"
const ROLLBACK_TICKS_MONITOR: StringName = &"netfox/Rollback ticks simulated"
const ROLLBACK_TICK_DURATION_MONITOR: StringName = &"netfox/Rollback tick duration (ms)"
const ROLLBACK_NODES_SIMULATED_MONITOR: StringName = &"netfox/Rollback nodes simulated"
const ROLLBACK_NODES_SIMULATED_PER_TICK_MONITOR: StringName = &"netfox/Rollback nodes simulated per tick (avg)"
const FULL_STATE_PROPERTIES_COUNT: StringName = &"netfox/Full state properties count"
const SENT_STATE_PROPERTIES_COUNT: StringName = &"netfox/Sent state properties count"
const SENT_STATE_PROPERTIES_RATIO: StringName = &"netfox/Sent state properties ratio"
var _network_loop_start: float = 0
var _network_loop_duration: float = 0
var _network_ticks: int = 0
var _network_ticks_accum: int = 0
var _rollback_loop_start: float = 0
var _rollback_loop_duration: float = 0
var _rollback_ticks: int = 0
var _rollback_ticks_accum: int = 0
var _rollback_nodes_simulated: int = 0
var _rollback_nodes_simulated_accum: int = 0
var _full_state_props: int = 0
var _full_state_props_accum: int = 0
var _sent_state_props: int = 0
var _sent_state_props_accum: int = 0
static var _logger: NetfoxLogger = NetfoxLogger._for_netfox("NetworkPerformance")
## Check if performance monitoring is enabled.
## [br][br]
## By default, monitoring is only enabled in debug builds
## ( see [method OS.is_debug_build] ). [br]
## Can be forced on with the [code]netfox_perf[/code] feature tag. [br]
## Can be forced off with the [code]netfox_noperf[/code] feature tag.
func is_enabled() -> bool:
if OS.has_feature("netfox_noperf"):
return false
if OS.has_feature("netfox_perf"):
return true
# This returns true in the editor too
return OS.is_debug_build()
## Get time spent in the last network tick loop, in millisec.
## [br]
## Note that this also includes time spent in the rollback tick loop.
func get_network_loop_duration_ms() -> float:
return _network_loop_duration * 1000
## Get the number of ticks simulated in the last network tick loop.
func get_network_ticks() -> int:
return _network_ticks
## Get time spent in the last rollback tick loop, in millisec.
func get_rollback_loop_duration_ms() -> float:
return _rollback_loop_duration * 1000
## Get the number of ticks resimulated in the last rollback tick loop.
func get_rollback_ticks() -> int:
return _rollback_ticks
## Get the average amount of time spent in a rollback tick during the last
## rollback loop, in millisec.
func get_rollback_tick_duration_ms() -> float:
return _rollback_loop_duration * 1000 / maxi(_rollback_ticks, 1)
## Get the number of nodes simulated during the last rollback loop.
func get_rollback_nodes_simulated() -> int:
return _rollback_nodes_simulated
## Get the number of nodes simulated per tick on average during the last
## rollback loop.
func get_rollback_nodes_simulated_per_tick() -> float:
return _rollback_nodes_simulated / maxf(1., _rollback_ticks)
func push_rollback_nodes_simulated(count: int):
_rollback_nodes_simulated_accum += count
## Get the number of properties in the full state recorded during the last tick
## loop.
func get_full_state_props_count() -> int:
return _full_state_props
## Get the number of properties actually sent during the last tick loop.
func get_sent_state_props_count() -> int:
return _sent_state_props
## Get the ratio of sent properties count to full state properties count.
##
## See [member get_full_state_props_count][br]
## See [member get_sent_state_props_count]
func get_sent_state_props_ratio() -> float:
return _sent_state_props / maxf(1., _full_state_props)
func push_full_state(state: Dictionary) -> void:
_full_state_props_accum += state.size()
func push_full_state_props(count: int) -> void:
_full_state_props_accum += count
func push_full_state_broadcast(state: Dictionary) -> void:
_full_state_props_accum += state.size() * (multiplayer.get_peers().size() - 1)
func push_sent_state(state: Dictionary) -> void:
_sent_state_props_accum += state.size()
func push_sent_state_props(count: int) -> void:
_sent_state_props_accum += count
func push_sent_state_broadcast(state: Dictionary) -> void:
_sent_state_props_accum += state.size() * (multiplayer.get_peers().size() - 1)
func _ready() -> void:
if not is_enabled():
_logger.debug("Network performance disabled")
return
_logger.debug("Network performance enabled, registering performance monitors")
Performance.add_custom_monitor(NETWORK_LOOP_DURATION_MONITOR, get_network_loop_duration_ms)
Performance.add_custom_monitor(ROLLBACK_LOOP_DURATION_MONITOR, get_rollback_loop_duration_ms)
Performance.add_custom_monitor(NETWORK_TICKS_MONITOR, get_network_ticks)
Performance.add_custom_monitor(ROLLBACK_TICKS_MONITOR, get_rollback_ticks)
Performance.add_custom_monitor(ROLLBACK_TICK_DURATION_MONITOR, get_rollback_tick_duration_ms)
Performance.add_custom_monitor(ROLLBACK_NODES_SIMULATED_MONITOR, get_rollback_nodes_simulated)
Performance.add_custom_monitor(ROLLBACK_NODES_SIMULATED_PER_TICK_MONITOR, get_rollback_nodes_simulated_per_tick)
Performance.add_custom_monitor(FULL_STATE_PROPERTIES_COUNT, get_full_state_props_count)
Performance.add_custom_monitor(SENT_STATE_PROPERTIES_COUNT, get_sent_state_props_count)
Performance.add_custom_monitor(SENT_STATE_PROPERTIES_RATIO, get_sent_state_props_ratio)
NetworkTime.before_tick_loop.connect(_before_tick_loop)
NetworkTime.on_tick.connect(_on_network_tick)
NetworkTime.after_tick_loop.connect(_after_tick_loop)
NetworkRollback.before_loop.connect(_before_rollback_loop)
NetworkRollback.on_process_tick.connect(_on_rollback_tick)
NetworkRollback.after_loop.connect(_after_rollback_loop)
func _before_tick_loop() -> void:
_network_loop_start = _time()
_network_ticks_accum = 0
func _on_network_tick(_dt, _t) -> void:
_network_ticks_accum += 1
func _after_tick_loop() -> void:
_network_loop_duration = _time() - _network_loop_start
_network_ticks = _network_ticks_accum
_full_state_props = _full_state_props_accum
_full_state_props_accum = 0
_sent_state_props = _sent_state_props_accum
_sent_state_props_accum = 0
func _before_rollback_loop() -> void:
_rollback_loop_start = _time()
_rollback_ticks_accum = 0
_rollback_nodes_simulated_accum = 0
func _on_rollback_tick(_t: int) -> void:
_rollback_ticks_accum += 1
func _after_rollback_loop() -> void:
_rollback_loop_duration = _time() - _rollback_loop_start
_rollback_ticks = _rollback_ticks_accum
_rollback_nodes_simulated = _rollback_nodes_simulated_accum
func _time() -> float:
return Time.get_unix_time_from_system()