更新godot ai到最新版本

This commit is contained in:
2026-09-12 22:48:37 +08:00
parent 7436359efd
commit 2027ca1c86
284 changed files with 45866 additions and 776 deletions
+86
View File
@@ -0,0 +1,86 @@
@tool
extends VBoxContainer
## Dock subpanel — renders the MCP request/response log buffer. Owns its own
## UI subtree, the line-count cursor, and the display-visibility toggle. It
## receives copied `{sequence, reset, lines}` values; neither this view nor its
## parent Dock retains the root-owned log buffer.
##
## Extracted from mcp_dock.gd as part of audit-v2 #360 — see the comment at
## the top of mcp_dock.gd for the broader extraction story.
signal logging_enabled_changed(enabled: bool)
const Dock := preload("res://addons/godot_ai/mcp_dock.gd")
const Settings := preload("res://addons/godot_ai/utils/settings.gd")
var _log_display: RichTextLabel
var _log_toggle: CheckButton
## Last `McpLogBuffer.total_logged()` value painted into the display. Tracking
## the buffer's monotonic sequence (rather than its bounded `total_count()`)
## keeps the viewer painting once the ring fills — a size-based cursor would
## freeze at MAX_LINES on every subsequent append. See PR #392 for the bug.
var _last_log_seq := 0
## Build the UI synchronously here so callers (and detached-tree tests that
## instantiate the dock with `McpDockScript.new()` and never enter the tree)
## can interact with the panel's controls right after `setup()`. Mirrors the
## pre-extraction inline-build behavior that test_dock.gd relies on.
##
## Idempotent: `_log_display == null` covers an unlikely double-`setup()` call
## without rebuilding (which would orphan the prior controls).
func setup() -> void:
if _log_display == null:
_build_ui()
func _build_ui() -> void:
add_child(HSeparator.new())
var log_header_row := HBoxContainer.new()
var log_header := Dock._make_header("MCP Log")
log_header.size_flags_horizontal = Control.SIZE_EXPAND_FILL
log_header_row.add_child(log_header)
_log_toggle = CheckButton.new()
_log_toggle.text = "Log"
## Restore the persisted choice — a hardcoded `true` here meant the
## toggle reset to noisy on every editor restart (#626).
_log_toggle.button_pressed = Settings.mcp_logging_enabled()
_log_toggle.toggled.connect(_on_log_toggled)
log_header_row.add_child(_log_toggle)
add_child(log_header_row)
_log_display = RichTextLabel.new()
_log_display.custom_minimum_size = Vector2(0, 80)
_log_display.scroll_following = true
_log_display.bbcode_enabled = false
_log_display.selection_enabled = true
_log_display.visible = _log_toggle.button_pressed
add_child(_log_display)
func sequence() -> int:
return _last_log_seq
func present_snapshot(snapshot: Dictionary) -> void:
if _log_display == null:
return
var seq := int(snapshot.get("sequence", _last_log_seq))
if bool(snapshot.get("reset", false)) or seq < _last_log_seq:
_log_display.clear()
_last_log_seq = 0
var lines: Array[String] = []
lines.assign(snapshot.get("lines", []))
for line in lines:
_log_display.add_text(line + "\n")
_last_log_seq = seq
func _on_log_toggled(enabled: bool) -> void:
Settings.set_mcp_logging_enabled(enabled)
_log_display.visible = enabled
logging_enabled_changed.emit(enabled)
@@ -0,0 +1 @@
uid://cr5nbnd6vj3b8
@@ -0,0 +1,106 @@
@tool
extends VBoxContainer
## Dock subpanel — port-change escape hatch surfaced inside the spawn-failure
## crash panel when a port is contested or an incompatible server cannot be reclaimed.
##
## It moves BOTH ports. A godot-ai server binds its HTTP and WebSocket ports
## together, so moving only the HTTP port onto a free number lands the next
## launch on a WebSocket port the previous server still holds, and the server
## dies at preflight ("WebSocket port 19630 is already in use"). Emits
## `port_apply_requested(new_http_port, new_ws_port)` after range-validation;
## the dock writes the EditorSettings and reloads the plugin.
##
## Extracted from mcp_dock.gd as part of audit-v2 #360 — see the comment at
## the top of mcp_dock.gd for the broader extraction story.
const ClientConfigurator := preload("res://addons/godot_ai/client_configurator.gd")
const PortResolver := preload("res://addons/godot_ai/utils/port_resolver.gd")
signal port_apply_requested(new_http_port: int, new_ws_port: int)
var _spinbox: SpinBox
var _ws_spinbox: SpinBox
## Bind probe used when seeding; tests substitute a deterministic one.
var port_in_use_probe: Callable = Callable(PortResolver, "is_port_in_use")
## Build the UI synchronously here so callers (and detached-tree tests that
## instantiate the dock with `McpDockScript.new()` and never enter the tree)
## can interact with the panel's controls right after `setup()`. Mirrors the
## pre-extraction inline-build behavior that test_dock.gd relies on.
##
## Idempotent: `_spinbox == null` covers an unlikely double-`setup()` call
## without rebuilding (which would orphan the prior controls).
func setup() -> void:
if _spinbox == null:
_build_ui()
func _build_ui() -> void:
add_theme_constant_override("separation", 4)
visible = false
var picker_row := HBoxContainer.new()
picker_row.add_theme_constant_override("separation", 6)
_spinbox = _port_spinbox(ClientConfigurator.http_port(), "Effective HTTP port")
picker_row.add_child(_spinbox)
_ws_spinbox = _port_spinbox(ClientConfigurator.ws_port(), "Effective WebSocket port")
picker_row.add_child(_ws_spinbox)
var apply_btn := Button.new()
apply_btn.text = "Apply + Reload"
apply_btn.tooltip_text = (
"Saves the effective HTTP and WebSocket ports to Editor Settings and reloads"
+ " the plugin so the server spawns on the new ports. Reconfigure your AI"
+ " clients afterwards so their bridges use the new ports."
)
apply_btn.pressed.connect(_on_apply_pressed)
picker_row.add_child(apply_btn)
add_child(picker_row)
static func _port_spinbox(value: int, tooltip: String) -> SpinBox:
var spinbox := SpinBox.new()
spinbox.min_value = ClientConfigurator.MIN_PORT
spinbox.max_value = ClientConfigurator.MAX_PORT
spinbox.step = 1
spinbox.value = value
spinbox.tooltip_text = tooltip
spinbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
return spinbox
## Seed both boxes every time the panel surfaces, so a stale value from a
## previous spawn-failure round cannot carry over. The diagnosed
## `conflict_port` and any port that is simply in use get a fresh free
## suggestion; a port that is free keeps its value, so clients whose entries
## carry it keep working. Note that this OVERWRITES unsaved user input — fine
## in practice because the dock only calls this on `server_status`
## transitions (`if server_status == _last_server_status: return`).
func seed_suggested_ports(conflict_port := 0) -> void:
if _spinbox == null:
return
var http := ClientConfigurator.http_port()
var ws := ClientConfigurator.ws_port()
if conflict_port == http or bool(port_in_use_probe.call(http)):
http = ClientConfigurator.suggest_free_port(http + 1)
if conflict_port == ws or ws == http or bool(port_in_use_probe.call(ws)):
ws = ClientConfigurator.suggest_free_port(ws + 1)
if ws == http:
ws = ClientConfigurator.suggest_free_port(ws + 1)
_spinbox.value = http
_ws_spinbox.value = ws
func _on_apply_pressed() -> void:
var new_http: int = int(_spinbox.value)
var new_ws: int = int(_ws_spinbox.value)
for port in [new_http, new_ws]:
if port < ClientConfigurator.MIN_PORT or port > ClientConfigurator.MAX_PORT:
return
if new_http == new_ws:
return
port_apply_requested.emit(new_http, new_ws)
@@ -0,0 +1 @@
uid://hlggbo1q65eq