This commit is contained in:
2026-01-16 21:31:48 +08:00
parent 1b36fb789a
commit 04673fc967
7 changed files with 179 additions and 34 deletions

View File

@@ -141,25 +141,32 @@ For each function call, return a JSON object within <tool_call></tool_call> tags
if (_overlayWindowOpen && !string.IsNullOrEmpty(_overlayWindowEventDefName))
{
string eventDefNameToRestore = _overlayWindowEventDefName;
float savedX = _overlayWindowX;
float savedY = _overlayWindowY;
LongEventHandler.ExecuteWhenFinished(() =>
{
try
{
var existingWindow = Find.WindowStack?.Windows?.OfType<WulaFallenEmpire.EventSystem.AI.UI.Overlay_WulaLink>().FirstOrDefault();
// Additional safety checks for load scenarios
if (Find.WindowStack == null || Find.World == null)
{
WulaLog.Debug("[WulaAI] Skipping overlay restore: game not fully loaded.");
return;
}
var existingWindow = Find.WindowStack.Windows?.OfType<WulaFallenEmpire.EventSystem.AI.UI.Overlay_WulaLink>().FirstOrDefault();
if (existingWindow == null)
{
var eventDef = DefDatabase<EventDef>.GetNamedSilentFail(eventDefNameToRestore);
if (eventDef != null)
{
var newWindow = new WulaFallenEmpire.EventSystem.AI.UI.Overlay_WulaLink(eventDef);
if (savedX >= 0f && savedY >= 0f)
{
newWindow.SetInitialPosition(savedX, savedY);
}
Find.WindowStack.Add(newWindow);
newWindow.ToggleMinimize(); // Start minimized
// Force position after everything else
if (_overlayWindowX >= 0f && _overlayWindowY >= 0f)
{
newWindow.windowRect.x = _overlayWindowX;
newWindow.windowRect.y = _overlayWindowY;
}
}
}
}

View File

@@ -195,9 +195,9 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
// Switch to Small UI Button
Rect switchBtnRect = new Rect(0f, 0f, 25f, 25f);
if (DrawHeaderButton(switchBtnRect, "-"))
if (DrawHeaderButton(switchBtnRect, "-"))
{
if (def != null)
if (def != null && Find.WindowStack != null)
{
var existing = Find.WindowStack.WindowOfType<Overlay_WulaLink>();
if (existing != null) existing.Expand();
@@ -210,7 +210,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
Rect personalityBtnRect = new Rect(0f, 30f, 25f, 25f);
if (DrawHeaderButton(personalityBtnRect, "P"))
{
Find.WindowStack.Add(new Dialog_ExtraPersonalityPrompt());
Find.WindowStack?.Add(new Dialog_ExtraPersonalityPrompt());
}
float margin = 15f;
@@ -854,7 +854,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
private string BuildThinkingStatus()
{
if (_core == null) return "Thinking...";
float elapsedSeconds = Mathf.Max(0f, Time.realtimeSinceStartup - _core.ThinkingStartTime);
float elapsedSeconds = Mathf.Max(0f, Time.realtimeSinceStartup - (_core.ThinkingStartTime));
string elapsedText = elapsedSeconds.ToString("0.0", CultureInfo.InvariantCulture);
return $"P.I.A is thinking... ({elapsedText}s Loop {_core.ThinkingPhaseIndex})";
}
@@ -945,22 +945,22 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
{
if (string.IsNullOrWhiteSpace(text)) return;
if (_core == null) return;
if (string.Equals(text.Trim(), "/clear", StringComparison.OrdinalIgnoreCase))
{
_isThinking = false;
_options.Clear();
_inputText = "";
// Core functionality for clear if implemented, or just UI clear
// For now, Dialog doesn't manage history, Core does.
// Core should handle /clear command via SendUserMessage theoretically,
// For now, Dialog doesn't manage history, Core does.
// Core should handle /clear command via SendUserMessage theoretically,
// or we call a hypothetical _core.ClearHistory().
// Based on previous code, SendUserMessage handles /clear logic inside Core.
}
_scrollToBottom = true;
_core.SendUserMessage(text);
_history = _core.GetHistorySnapshot();
_history = _core.GetHistorySnapshot() ?? new List<(string role, string message)>();
}
private void DrawConversationOptions(Rect rect, List<EventOption> options)

View File

@@ -129,14 +129,14 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
public void Expand()
{
if (_isMinimized) ToggleMinimize();
Find.WindowStack.Notify_ManuallySetFocus(this);
Find.WindowStack?.Notify_ManuallySetFocus(this);
}
public override void PreOpen()
{
base.PreOpen();
// Connect to Core
_core = Find.World.GetComponent<AIIntelligenceCore>();
// Connect to Core - with null safety for load scenarios
_core = Find.World?.GetComponent<AIIntelligenceCore>();
if (_core != null)
{
_core.InitializeConversation(_eventDefName);
@@ -167,7 +167,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
{
_unreadCount++;
// Spawn Notification Bubble
Find.WindowStack.Add(new Overlay_WulaLink_Notification(msg));
Find.WindowStack?.Add(new Overlay_WulaLink_Notification(msg));
}
}
@@ -221,15 +221,15 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
private void DrawMinimized(Rect rect)
{
// AI 核心挂件背景
Widgets.DrawBoxSolid(rect, new Color(0.1f, 0.1f, 0.1f, 0.9f));
Widgets.DrawBoxSolid(rect, new Color(0.1f, 0.1f, 0.1f, 0.9f));
GUI.color = WulaLinkStyles.HeaderColor;
Widgets.DrawBox(rect, 2);
Widgets.DrawBox(rect, 2);
GUI.color = Color.white;
// 左侧:大型方形头像
float avaSize = rect.height - 16f;
Rect avatarRect = new Rect(8f, 8f, avaSize, avaSize);
int expId = _core?.ExpressionId ?? 1;
string portraitPath = "Wula/Storyteller/WULA_Legion_TINY";
Texture2D portrait = ContentFinder<Texture2D>.Get(portraitPath, false);
@@ -245,17 +245,18 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
// 右侧:状态展示
float rightContentX = avatarRect.xMax + 12f;
float btnWidth = 30f;
// Status Info
string status = _core.IsThinking ? "Thinking..." : "Standby";
Color statusColor = _core.IsThinking ? Color.yellow : Color.green;
// Status Info - with null safety
bool isThinking = _core?.IsThinking ?? false;
string status = isThinking ? "Thinking..." : "Standby";
Color statusColor = isThinking ? Color.yellow : Color.green;
// 绘制状态文字
Rect textRect = new Rect(rightContentX, 0, rect.width - rightContentX - btnWidth - 5f, rect.height);
Text.Anchor = TextAnchor.MiddleLeft;
Text.Font = GameFont.Small;
GUI.color = statusColor;
Widgets.Label(textRect, _core.IsThinking ? BuildThinkingStatus() : "Standby");
Widgets.Label(textRect, isThinking ? BuildThinkingStatus() : "Standby");
GUI.color = Color.white;
// 右侧:小巧的展开按钮
@@ -290,13 +291,14 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
Widgets.DrawLineHorizontal(rect.x, rect.y, rect.width);
string contextInfo = "Context: None";
if (Find.Selector.SingleSelectedThing != null)
var selector = Find.Selector;
if (selector?.SingleSelectedThing != null)
{
contextInfo = $"Context: [{Find.Selector.SingleSelectedThing.LabelCap}]";
contextInfo = $"Context: [{selector.SingleSelectedThing.LabelCap}]";
}
else if (Find.Selector.SelectedObjects.Count > 1)
else if (selector?.SelectedObjects?.Count > 1)
{
contextInfo = $"Context: {Find.Selector.SelectedObjects.Count} objects selected";
contextInfo = $"Context: {selector.SelectedObjects.Count} objects selected";
}
Text.Anchor = TextAnchor.MiddleLeft;
@@ -917,12 +919,12 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
bool sendClicked = DrawCustomButton(btnRect, ">", !string.IsNullOrWhiteSpace(_inputText));
if (sendClicked || enterPressed)
{
if (!string.IsNullOrWhiteSpace(_inputText))
if (!string.IsNullOrWhiteSpace(_inputText) && _core != null)
{
bool wasFocused = GUI.GetNameOfFocusedControl() == "WulaInput";
_core.SendUserMessage(_inputText);
_inputText = "";
if (wasFocused) GUI.FocusControl("WulaInput");
if (wasFocused) GUI.FocusControl("WulaInput");
}
}