From d9025128e091d0de6b313b1de0135852785eeef4 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Thu, 29 Jan 2026 15:45:06 +0800 Subject: [PATCH] Integrate Nakama managers and enhance powerup system Added Nakama and related manager scripts to autoload in project.godot and updated input mappings. Improved powerup_manager.gd with new methods and aliases for compatibility and gameplay rewards. Refactored ui_manager.gd to better initialize UI elements and removed unused code. Added playerboard_is_empty to player.gd for board state checks. Minor formatting changes in Nakama C# utility files for consistency. --- .../dotnet-utils/GodotHttpAdapter.cs | 10 +- .../dotnet-utils/GodotLogger.cs | 102 +++++++++--------- .../dotnet-utils/GodotWebSocketAdapter.cs | 30 +++--- project.godot | 72 +++++++++++-- scenes/player.gd | 6 ++ scripts/managers/powerup_manager.gd | 34 ++++++ scripts/managers/ui_manager.gd | 18 ++-- scripts/ui/powerup_inventory_ui.gd.uid | 1 + 8 files changed, 189 insertions(+), 84 deletions(-) create mode 100644 scripts/ui/powerup_inventory_ui.gd.uid diff --git a/addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs b/addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs index 74a157c..bf88693 100644 --- a/addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs +++ b/addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs @@ -21,11 +21,11 @@ using Godot; namespace Nakama { - /// - /// An Http adapter which uses Godot's HttpRequest node. + /// + /// An Http adapter which uses Godot's HttpRequest node. /// /// - /// Note Content-Type header is always set as 'application/json'. + /// Note Content-Type header is always set as 'application/json'. /// public partial class GodotHttpAdapter : Node, IHttpAdapter { @@ -73,7 +73,7 @@ namespace Nakama { AddChild(req); req.Request(uri.ToString(), headers_array, godot_method, body_string); - Logger?.InfoFormat("Send: method='{0}', uri='{1}', body='{2}'", method, uri, body_string); + Logger?.InfoFormat("Send: method='{0}', uri='{1}', body='{2}'", method, uri, body_string); Variant[] resultObjects = await ToSignal(req, "request_completed"); @@ -83,7 +83,7 @@ namespace Nakama { req.QueueFree(); - Logger?.InfoFormat("Received: status={0}, contents='{1}'", response_code, response_body); + Logger?.InfoFormat("Received: status={0}, contents='{1}'", response_code, response_body); if (result == HttpRequest.Result.Success && response_code >= 200 && response_code <= 299) { return response_body; diff --git a/addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs b/addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs index 5aa7f1e..9051dc4 100644 --- a/addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs +++ b/addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs @@ -17,63 +17,63 @@ using Godot; namespace Nakama { - /// - /// A logger which prints to the Godot console. - /// - public class GodotLogger : ILogger { + /// + /// A logger which prints to the Godot console. + /// + public class GodotLogger : ILogger { - /// - /// The log level. - /// - public enum LogLevel { - NONE, - ERROR, - WARNING, - INFO, - DEBUG, - } + /// + /// The log level. + /// + public enum LogLevel { + NONE, + ERROR, + WARNING, + INFO, + DEBUG, + } - private string module; - private LogLevel level; + private string module; + private LogLevel level; - /// - /// Constructs a GodotLogger. - /// - /// The label to use for log entries. - /// The log level (or lower) to print to the console. - public GodotLogger(string p_module = "Nakama", LogLevel p_level = LogLevel.ERROR) { - module = p_module; - level = p_level; - } + /// + /// Constructs a GodotLogger. + /// + /// The label to use for log entries. + /// The log level (or lower) to print to the console. + public GodotLogger(string p_module = "Nakama", LogLevel p_level = LogLevel.ERROR) { + module = p_module; + level = p_level; + } - /// - public void ErrorFormat(string format, params object[] args) { - if (level >= LogLevel.ERROR) { - GD.PrintErr("=== " + module + " : ERROR === " + String.Format(format, args)); - } - } + /// + public void ErrorFormat(string format, params object[] args) { + if (level >= LogLevel.ERROR) { + GD.PrintErr("=== " + module + " : ERROR === " + String.Format(format, args)); + } + } - /// - public void WarnFormat(string format, params object[] args) { - if (level >= LogLevel.WARNING) { - GD.Print("=== " + module + " : WARN === " + String.Format(format, args)); - } - } + /// + public void WarnFormat(string format, params object[] args) { + if (level >= LogLevel.WARNING) { + GD.Print("=== " + module + " : WARN === " + String.Format(format, args)); + } + } - /// - public void InfoFormat(string format, params object[] args) { - if (level >= LogLevel.INFO) { - GD.Print("=== " + module + " : INFO === " + String.Format(format, args)); - } - } + /// + public void InfoFormat(string format, params object[] args) { + if (level >= LogLevel.INFO) { + GD.Print("=== " + module + " : INFO === " + String.Format(format, args)); + } + } - /// - public void DebugFormat(string format, params object[] args) { - if (level >= LogLevel.DEBUG) { - GD.Print("=== " + module + " : DEBUG === " + String.Format(format, args)); - } - } + /// + public void DebugFormat(string format, params object[] args) { + if (level >= LogLevel.DEBUG) { + GD.Print("=== " + module + " : DEBUG === " + String.Format(format, args)); + } + } - } + } -} \ No newline at end of file +} diff --git a/addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs b/addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs index 8ac17e7..087b801 100644 --- a/addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs +++ b/addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs @@ -19,23 +19,23 @@ using Godot; namespace Nakama { - /// - /// An exception that is thrown when the WebSocket is unable to connect. - /// - public class GodotWebSocketConnectionException : Exception { - public GodotWebSocketConnectionException(string message = "WebSocket unable to connect") - : base(message) { } - } + /// + /// An exception that is thrown when the WebSocket is unable to connect. + /// + public class GodotWebSocketConnectionException : Exception { + public GodotWebSocketConnectionException(string message = "WebSocket unable to connect") + : base(message) { } + } - /// - /// An exception that is thrown when the WebSocket is unable to send. - /// - public class GodotWebSocketSendException : Exception { - public GodotWebSocketSendException() : base("Unable to send over WebSocket") { } - } + /// + /// An exception that is thrown when the WebSocket is unable to send. + /// + public class GodotWebSocketSendException : Exception { + public GodotWebSocketSendException() : base("Unable to send over WebSocket") { } + } - /// - /// A socket adapter which uses Godot's WebSocketPeer. + /// + /// A socket adapter which uses Godot's WebSocketPeer. /// public partial class GodotWebSocketAdapter : Node, ISocketAdapter { diff --git a/project.godot b/project.godot index 074c239..dea1682 100644 --- a/project.godot +++ b/project.godot @@ -11,14 +11,24 @@ config_version=5 [application] config/name="tekton-local" -run/main_scene="res://scenes/main_scene.tscn" +run/main_scene="uid://dxn87yj8qnfpp" config/features=PackedStringArray("4.5", "Forward Plus") config/icon="res://icon.svg" [autoload] -BeehaveGlobalMetrics="*res://addons/beehave/metrics/beehave_global_metrics.gd" -BeehaveGlobalDebugger="*res://addons/beehave/debug/global_debugger.gd" +Nakama="*res://addons/com.heroiclabs.nakama/Nakama.gd" +NakamaManager="*res://scripts/nakama_manager.gd" +AuthManager="*res://scripts/managers/auth_manager.gd" +LobbyManager="*res://scripts/managers/lobby_manager.gd" +UserProfileManager="*res://scripts/managers/user_profile_manager.gd" +GameStateManager="*res://scripts/managers/game_state_manager.gd" +NetworkManager="*res://scripts/network_manager.gd" +TurnManager="*res://scripts/managers/turn_manager.gd" +GoalManager="*res://scripts/managers/goal_manager.gd" +PlayerManager="*res://scripts/managers/player_manager.gd" +GoalsCycleManager="*res://scripts/managers/goals_cycle_manager.gd" +Satori="*res://addons/com.heroiclabs.nakama/Satori.gd" [display] @@ -30,17 +40,67 @@ window/stretch/mode="viewport" [editor_plugins] -enabled=PackedStringArray("res://addons/enhanced_gridmap/plugin.cfg") +enabled=PackedStringArray("res://addons/enhanced_gridmap/plugin.cfg", "res://addons/com.heroiclabs.nakama/plugin.cfg") [input] grab_item={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) ] } put_item={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null) +] +} +move_north={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +move_south={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +move_west={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":0,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +move_east={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":68,"physical_keycode":0,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +move_northeast={ +"deadzone": 0.5, +"events": [] +} +move_northwest={ +"deadzone": 0.5, +"events": [] +} +move_southeast={ +"deadzone": 0.5, +"events": [] +} +move_southwest={ +"deadzone": 0.5, +"events": [] +} +action_grab={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) +] +} +action_put={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null) ] } diff --git a/scenes/player.gd b/scenes/player.gd index 2833bc4..14d53e1 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -645,6 +645,12 @@ func apply_stagger(duration: float = 1.5): else: _apply_tint_recursive(self, Color.WHITE) # Remove tint +func playerboard_is_empty() -> bool: + for item in playerboard: + if item != -1: + return false + return true + func drop_random_item(): if playerboard_is_empty(): return diff --git a/scripts/managers/powerup_manager.gd b/scripts/managers/powerup_manager.gd index f4543b2..add459e 100644 --- a/scripts/managers/powerup_manager.gd +++ b/scripts/managers/powerup_manager.gd @@ -13,6 +13,16 @@ var goal_manager: Node # Boost State var current_boost: float = 0.0 +# Alias for compatibility with BotStrategicPlanner +var current_points: float: + get: + return current_boost + set(value): + current_boost = value + +# Also alias MAX_POINTS +const MAX_POINTS = MAX_BOOST + signal points_changed(current: int, max_points: int) # Reused for UI (int casting) signal bar_filled() signal boost_reset() @@ -93,3 +103,27 @@ func get_max_points() -> int: func get_fill_percentage() -> float: return current_boost / MAX_BOOST +func can_use_special() -> bool: + return current_boost >= MAX_BOOST + +func use_special_effect() -> bool: + if not can_use_special(): + return false + + # Consume boost + reset_boost() + return true + +func acquire_smash_bonus(): + current_boost += 25.0 # Add 25% boost + current_boost = min(current_boost, MAX_BOOST) + emit_signal("points_changed", int(current_boost), int(MAX_BOOST)) + if current_boost >= MAX_BOOST: + _on_boost_full() + +func add_goal_completion_reward(): + current_boost += 50.0 # Reward for completing goal + current_boost = min(current_boost, MAX_BOOST) + emit_signal("points_changed", int(current_boost), int(MAX_BOOST)) + if current_boost >= MAX_BOOST: + _on_boost_full() diff --git a/scripts/managers/ui_manager.gd b/scripts/managers/ui_manager.gd index ac399ce..aeff466 100644 --- a/scripts/managers/ui_manager.gd +++ b/scripts/managers/ui_manager.gd @@ -16,7 +16,9 @@ var move_button var grab_button var put_button var randomize_button -var victory_ui_scene = preload("res://scenes/ui/victory_ui.tscn") +var arrange_button +# var victory_ui_scene = preload("res://scenes/ui/victory_ui.tscn") +var victory_ui_scene = null var powerup_inventory_ui_script = preload("res://scripts/ui/powerup_inventory_ui.gd") var main_menu_instance @@ -43,7 +45,13 @@ func initialize(player_node): powerup_inventory_ui = player_node.get_node_or_null("PowerUpInventoryUI") # Get node references from main scene - randomize_button = player_node.get_node("ActionMenu/ActionButtonContainer/RandomizeButton") # renamed main_node to player_node which is Main + action_menu = player_node.get_node("ActionMenu") + + var button_container = player_node.get_node("ActionMenu/ActionButtonContainer") + move_button = button_container.get_node("MoveButton") + grab_button = button_container.get_node("GrabButton") + put_button = button_container.get_node("PutButton") + randomize_button = button_container.get_node("RandomizeButton") # renamed main_node to player_node which is Main arrange_button = player_node.get_node("ActionMenu/ActionButtonContainer/ArrangeButton") playerboard_ui = player_node.get_node("PlayerboardUI") @@ -212,11 +220,7 @@ func update_button_states(): put_button.disabled = false arrange_button.disabled = false -func set_local_player(player): - local_player_character = player - - # Connect to powerup signals with deferred call (manager needs time to initialize) - _connect_powerup_manager_deferred(player) + func _connect_powerup_manager_deferred(player): """Wait for PowerUpManager to be initialized before connecting.""" diff --git a/scripts/ui/powerup_inventory_ui.gd.uid b/scripts/ui/powerup_inventory_ui.gd.uid new file mode 100644 index 0000000..7b450ce --- /dev/null +++ b/scripts/ui/powerup_inventory_ui.gd.uid @@ -0,0 +1 @@ +uid://86ikh0wuqk7v