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)
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
extends Node
|
||||
|
||||
# Settings
|
||||
var _is_enabled: bool = ProjectSettings.get_setting(&"netfox/extras/auto_tile_windows", false)
|
||||
var _is_borderless: bool = ProjectSettings.get_setting(&"netfox/extras/borderless", false)
|
||||
var _tile_screen: int = ProjectSettings.get_setting(&"netfox/extras/screen", 0)
|
||||
|
||||
# Hash the game name, so we always get a valid filename
|
||||
var _prefix: String = "netfox-window-tiler-%x" % [ProjectSettings.get_setting(&"application/config/name").hash()]
|
||||
|
||||
var _sid: String = "%x" % [hash(int(Time.get_unix_time_from_system() / 2.))]
|
||||
var _uid: String = "%d" % [Time.get_unix_time_from_system() * 1000_0000.]
|
||||
|
||||
static var _logger: NetfoxLogger = NetfoxLogger._for_extras("WindowTiler")
|
||||
|
||||
func _ready() -> void:
|
||||
# Running on a non-editor (export template) build
|
||||
if OS.has_feature("template"):
|
||||
return
|
||||
|
||||
# Running in headless mode
|
||||
if DisplayServer.get_name() == "headless":
|
||||
return
|
||||
|
||||
# Running in CI
|
||||
for env_var in ["CI", "NETFOX_CI"]:
|
||||
if OS.get_environment(env_var) != "":
|
||||
_logger.debug("Environment variable %s set, disabling", [env_var])
|
||||
return
|
||||
|
||||
# Cleanup in case some files were left
|
||||
_cleanup()
|
||||
|
||||
# Running embedded in editor
|
||||
if _is_embedded():
|
||||
return
|
||||
|
||||
# Don't tile if disabled
|
||||
if not _is_enabled:
|
||||
return
|
||||
|
||||
_logger.debug("Tiling with sid: %s, uid: %s", [_sid, _uid])
|
||||
|
||||
var err = _make_lock(_sid, _uid)
|
||||
if err != Error.OK:
|
||||
_logger.warning("Failed to create lock for tiling, reason: %s", [error_string(err)])
|
||||
return
|
||||
|
||||
# Search for locks, stop once no new locks are found
|
||||
var locks = []
|
||||
await get_tree().create_timer(0.25).timeout
|
||||
for i in range(20):
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
var new_locks = _list_lock_ids()
|
||||
|
||||
if locks == new_locks:
|
||||
break
|
||||
|
||||
locks = new_locks
|
||||
|
||||
var tile_count = locks.size()
|
||||
var idx = locks.find(_uid)
|
||||
|
||||
_logger.debug("Tiling as idx %d / %d - %s in %s", [idx, tile_count, _uid, locks])
|
||||
_tile_window(idx, tile_count)
|
||||
|
||||
func _is_embedded() -> bool:
|
||||
if Engine.has_method("is_embedded_in_editor"):
|
||||
return Engine.call("is_embedded_in_editor")
|
||||
return false
|
||||
|
||||
func _make_lock(sid: String, uid: String) -> Error:
|
||||
var path = "%s/%s-%s-%s" % [OS.get_cache_dir(), _prefix, sid, uid]
|
||||
var file := FileAccess.open(path, FileAccess.WRITE)
|
||||
|
||||
if file == null:
|
||||
return FileAccess.get_open_error()
|
||||
|
||||
file.close()
|
||||
return Error.OK
|
||||
|
||||
func _list_lock_ids() -> Array[String]:
|
||||
var result: Array[String] = []
|
||||
var dir := DirAccess.open(OS.get_cache_dir())
|
||||
|
||||
if dir:
|
||||
for f in dir.get_files():
|
||||
if f.begins_with(_prefix):
|
||||
result.append(_get_uid(f))
|
||||
|
||||
return result
|
||||
|
||||
func _cleanup():
|
||||
var result: Array[String] = []
|
||||
var dir := DirAccess.open(OS.get_cache_dir())
|
||||
|
||||
if dir:
|
||||
for f in dir.get_files():
|
||||
if f.begins_with(_prefix) and _get_sid(f) != _sid:
|
||||
_logger.trace("Cleaned up lock: %s", [f])
|
||||
dir.remove(OS.get_cache_dir() + "/" + f)
|
||||
|
||||
func _get_sid(filename: String) -> String:
|
||||
return filename.substr(_prefix.length() + 1).get_slice("-", 0)
|
||||
|
||||
func _get_uid(filename: String) -> String:
|
||||
return filename.substr(_prefix.length() + 1).get_slice("-", 1)
|
||||
|
||||
func _tile_window(i: int, total: int) -> void:
|
||||
var screen = _tile_screen
|
||||
var screen_rect = DisplayServer.screen_get_usable_rect(screen)
|
||||
|
||||
var window: Window = get_tree().get_root()
|
||||
window.set_current_screen(screen)
|
||||
|
||||
if total == 1:
|
||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MAXIMIZED)
|
||||
return
|
||||
|
||||
window.borderless = _is_borderless
|
||||
|
||||
# Divide up the screen
|
||||
var windows_per_row = int(ceil(sqrt(total)))
|
||||
var windows_per_col = int(ceil(total / float(windows_per_row)))
|
||||
var window_size = Vector2(
|
||||
screen_rect.size.x / windows_per_row, screen_rect.size.y / windows_per_col
|
||||
)
|
||||
|
||||
window.set_size(window_size)
|
||||
|
||||
# Position of the window based on index.
|
||||
var row = i / windows_per_row
|
||||
var col = i % windows_per_row
|
||||
|
||||
var x = screen_rect.position.x + col * window_size.x
|
||||
var y = screen_rect.position.y + row * window_size.y
|
||||
|
||||
window.set_position(Vector2(x, y))
|
||||
Reference in New Issue
Block a user