Files
tactical-shooter/addons/netfox.internals/logger.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

209 lines
6.2 KiB
GDScript

extends RefCounted
class_name NetfoxLogger
## Logger implementation for use with netfox
##
## NetfoxLoggers implement distinct log levels. These can be used to filter
## which messages are actually emitted. All messages are output using [method
## @GlobalScope.print]. Warnings and errors are also pushed to the debug panel,
## using [method @GlobalScope.push_warning] and [method @GlobalScope.push_error]
## respectively, if [member push_to_debugger] is enabled.
## [br][br]
## Every logger has a name, and belongs to a module. Logging level can be
## overridden per module, using [member module_log_level].
## [br][br]
## Loggers also support tags. Tags can be used to provide extra pieces of
## information that are logged with each message. Some tags are provided by
## netfox. Additional tags can be added using [method register_tag].
##
## @tutorial(Logging Guide): https://foxssake.github.io/netfox/latest/netfox/guides/logging/
enum {
LOG_ALL, ## Filter level to log every message
LOG_TRACE, ## Trace logs, the most verbose level
LOG_DEBUG, ## Debug logs
LOG_INFO, ## Info logs
LOG_WARN, ## Warnings
LOG_ERROR, ## Errors
LOG_NONE ## Filter level to log no messages
}
## Default log level to fall back on, if not configured
const DEFAULT_LOG_LEVEL := LOG_DEBUG
const _LEVEL_PREFIXES: Array[String] = [
"",
"TRC",
"DBG",
"INF",
"WRN",
"ERR",
""
]
## Global logging level, used by all loggers
static var log_level: int
## Per-module logging level, used only by loggers belonging to the given module
## [br][br]
## This is a dictionary that associates module names ( strings ) to log levels
## ( int, e.g. [constant LOG_DEBUG] ).
static var module_log_level: Dictionary
## Set to true to enable calling [@GlobalScope.push_warning] and
## [@GlobalScope.push_error]
static var push_to_debugger := true
static var _tags: Dictionary = {}
static var _ordered_tags: Array[Callable] = []
## Logger module
var module: String
## Logger name
var name: String
## Register a tag
## [br][br]
## Tags are callables that provide pieces of context, included in all log
## messges. The [param tag] callable must return a string.
static func register_tag(tag: Callable, priority: int = 0) -> void:
# Save tag
if not _tags.has(priority):
_tags[priority] = [tag]
else:
_tags[priority].push_back(tag)
# Recalculate tag order
_ordered_tags.clear()
var prio_groups = _tags.keys()
prio_groups.sort()
for prio_group in prio_groups:
var tag_group = _tags[prio_group]
_ordered_tags.append_array(tag_group)
## Free an already registered tag
static func free_tag(tag: Callable) -> void:
for priority in _tags.keys():
var priority_group := _tags[priority] as Array
priority_group.erase(tag)
# NOTE: Arrays are passed as reference, no need to re-assign after modifying
if priority_group.is_empty():
_tags.erase(priority)
_ordered_tags.erase(tag)
static func _static_init():
log_level = ProjectSettings.get_setting(&"netfox/logging/log_level", DEFAULT_LOG_LEVEL)
module_log_level = {
"netfox": ProjectSettings.get_setting(&"netfox/logging/netfox_log_level", DEFAULT_LOG_LEVEL),
"netfox.noray": ProjectSettings.get_setting(&"netfox/logging/netfox_noray_log_level", DEFAULT_LOG_LEVEL),
"netfox.extras": ProjectSettings.get_setting(&"netfox/logging/netfox_extras_log_level", DEFAULT_LOG_LEVEL)
}
static func _for_netfox(p_name: String) -> NetfoxLogger:
return NetfoxLogger.new("netfox", p_name)
static func _for_noray(p_name: String) -> NetfoxLogger:
return NetfoxLogger.new("netfox.noray", p_name)
static func _for_extras(p_name: String) -> NetfoxLogger:
return NetfoxLogger.new("netfox.extras", p_name)
static func _make_setting(name: String) -> Dictionary:
return {
"name": name,
"value": DEFAULT_LOG_LEVEL,
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "All,Trace,Debug,Info,Warning,Error,None"
}
func _init(p_module: String, p_name: String):
module = p_module
name = p_name
## Log a trace message
## [br][br]
## Traces are the most verbose, usually used for drilling down into very niche
## bugs.
func trace(text: String, values: Array = []):
_log_text(text, values, LOG_TRACE)
## Log a debug message
## [br][br]
## Debug messages are verbose, usually used to reconstruct and investigate bugs.
func debug(text: String, values: Array = []):
_log_text(text, values, LOG_DEBUG)
## Log an info message
## [br][br]
## Info messages provide general notifications about application events.
func info(text: String, values: Array = []):
_log_text(text, values, LOG_INFO)
## Log a warning message
## [br][br]
## This is also forwarded to [method @GlobalScope.push_warning], if enabled with
## [member push_to_debugger]. Warning messages usually indicate that something
## has gone wrong, but is recoverable.
func warning(text: String, values: Array = []):
if _check_log_level(LOG_WARN):
var formatted_text = _format_text(text, values, LOG_WARN)
if push_to_debugger:
push_warning(formatted_text)
# Print so it shows up in the Output panel too
print(formatted_text)
## Log an error message
## [br][br]
## This is also forwarded to [method @GlobalScope.push_error], if enabled with
## [member push_to_debugger]. Error messages usually indicate an issue that
## can't be recovered from.
func error(text: String, values: Array = []):
if _check_log_level(LOG_ERROR):
var formatted_text = _format_text(text, values, LOG_ERROR)
if push_to_debugger:
push_error(formatted_text)
# Print so it shows up in the Output panel too
print(formatted_text)
func _check_log_level(level: int) -> bool:
var cmp_level = log_level
if level < cmp_level:
return false
if module_log_level.has(module):
var module_level = module_log_level.get(module)
return level >= module_level
return true
func _format_text(text: String, values: Array, level: int) -> String:
level = clampi(level, LOG_TRACE, LOG_ERROR)
var result := PackedStringArray()
result.append("[%s]" % [_LEVEL_PREFIXES[level]])
for tag in _ordered_tags:
result.append("[%s]" % [tag.call()])
result.append("[%s::%s] " % [module, name])
if values.is_empty():
result.append(text)
else:
result.append(text % values)
return "".join(result)
func _log_text(text: String, values: Array, level: int):
if _check_log_level(level):
print(_format_text(text, values, level))