Files
tactical-shooter/addons/netfox/network-events.gd
T
shawn e7299b17e9 Phase 7: netfox + godot-jolt stack upgrade
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)
2026-07-02 17:39:22 -04:00

149 lines
4.3 KiB
GDScript

extends Node
## This class provides convenience signals for multiplayer games.
##
## While the client start/stop and peer join/leave events are trivial, the
## server side has no similar events. This means that if you'd like to add some
## funcionality that should happen on server start, you either have to couple
## the code ( i.e. call it wherever you start the server ) or introduce a custom
## event to decouple your code from your network init code.
##
## By providing these convenience events, you can forego all that and instead
## just listen to a single signal that should work no matter what.
##
## [i]Note:[/i] This class also manages [NetworkTime] start/stop, so as long as
## network events are enabled, you don't need to manually call start/stop.
## Event emitted when the [MultiplayerAPI] is changed
signal on_multiplayer_change(old: MultiplayerAPI, new: MultiplayerAPI)
## Event emitted when the server starts
signal on_server_start()
## Event emitted when the server stops for any reason
signal on_server_stop()
## Event emitted when the client starts
signal on_client_start(id: int)
## Event emitted when the client stops.
##
## This can happen due to either the client itself or the server disconnecting
## for whatever reason.
signal on_client_stop()
## Event emitted when a new peer joins the game.
signal on_peer_join(id: int)
## Event emitted when a peer leaves the game.
signal on_peer_leave(id: int)
## Whether the events are enabled.
##
## Events are only emitted when it's enabled. Disabling this can free up some
## performance, as when enabled, the multiplayer API and the host are
## continuously checked for changes.
##
## The initial value is taken from the Netfox project settings.
var enabled: bool:
get: return _enabled
set(v): _set_enabled(v)
var _is_server: bool = false
var _multiplayer: MultiplayerAPI
var _enabled: bool = false
## Check if we're running as server.
func is_server() -> bool:
if multiplayer == null:
return false
var peer := multiplayer.multiplayer_peer
if peer == null:
return false
if peer is OfflineMultiplayerPeer:
return false
if peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED:
return false
if not multiplayer.is_server():
return false
return true
func _ready() -> void:
NetfoxLogger.register_tag(_get_peer_id_tag, -99)
enabled = ProjectSettings.get_setting(&"netfox/events/enabled", true)
# Automatically start ticking when entering multiplayer and stop when
# leaving multiplayer
on_server_start.connect(NetworkTime.start)
on_server_stop.connect(NetworkTime.stop)
on_client_start.connect(func(id): NetworkTime.start())
on_client_stop.connect(NetworkTime.stop)
func _exit_tree() -> void:
NetfoxLogger.free_tag(_get_peer_id_tag)
func _get_peer_id_tag() -> String:
return "#%d" % multiplayer.get_unique_id()
func _process(_delta: float) -> void:
if multiplayer != _multiplayer:
_disconnect_handlers(_multiplayer)
_connect_handlers(multiplayer)
on_multiplayer_change.emit(_multiplayer, multiplayer)
_multiplayer = multiplayer
if not _is_server and is_server():
_is_server = true
on_server_start.emit()
if _is_server and not is_server():
_is_server = false
on_server_stop.emit()
func _connect_handlers(mp: MultiplayerAPI) -> void:
if mp == null:
return
mp.connected_to_server.connect(_handle_connected_to_server)
mp.server_disconnected.connect(_handle_server_disconnected)
mp.peer_connected.connect(_handle_peer_connected)
mp.peer_disconnected.connect(_handle_peer_disconnected)
func _disconnect_handlers(mp: MultiplayerAPI) -> void:
if mp == null:
return
mp.connected_to_server.disconnect(_handle_connected_to_server)
mp.server_disconnected.disconnect(_handle_server_disconnected)
mp.peer_connected.disconnect(_handle_peer_connected)
mp.peer_disconnected.disconnect(_handle_peer_disconnected)
func _handle_connected_to_server() -> void:
on_client_start.emit(multiplayer.get_unique_id())
func _handle_server_disconnected() -> void:
on_client_stop.emit()
func _handle_peer_connected(id: int) -> void:
on_peer_join.emit(id)
func _handle_peer_disconnected(id: int) -> void:
on_peer_leave.emit(id)
func _set_enabled(enable: bool) -> void:
if _enabled and not enable:
_disconnect_handlers(_multiplayer)
_multiplayer = null
if not _enabled and enable:
_multiplayer = multiplayer
_connect_handlers(_multiplayer)
_enabled = enable
set_process(enable)