This commit is contained in:
2025-12-27 16:26:38 +08:00
parent 62f7c125ab
commit 6db785307c
18 changed files with 3878 additions and 583 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Verse;
using RimWorld;
using LudeonTK;
using WulaFallenEmpire.EventSystem.AI.UI;
namespace WulaFallenEmpire.EventSystem.AI
{
public static class DebugActions_WulaLink
{
[DebugAction("WulaLink", "Open WulaLink UI", actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.Playing)]
public static void OpenWulaLink()
{
// Find a suitable event def or create a generic one
EventDef def = DefDatabase<EventDef>.AllDefs.FirstOrDefault();
if (def == null)
{
Messages.Message("No EventDef found to initialize WulaLink.", MessageTypeDefOf.RejectInput, false);
return;
}
Find.WindowStack.Add(new Overlay_WulaLink(def));
}
}
}

View File

@@ -1,6 +1,6 @@
using System;
using Verse;
using WulaFallenEmpire.EventSystem.AI.UI;
using WulaFallenEmpire.EventSystem.AI;
namespace WulaFallenEmpire.EventSystem.AI.Tools
{
@@ -21,13 +21,13 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
{
if (int.TryParse(idStr, out id))
{
var window = Dialog_AIConversation.Instance ?? Find.WindowStack.WindowOfType<Dialog_AIConversation>();
if (window != null)
var core = AIIntelligenceCore.Instance;
if (core != null)
{
window.SetPortrait(id);
core.SetPortrait(id);
return $"Expression changed to {id}.";
}
return "Error: Dialog window not found.";
return "Error: AI Core not found.";
}
return "Error: Invalid arguments. 'expression_id' must be an integer.";
}
@@ -40,4 +40,4 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
}
}
}
}
}

View File

@@ -6,7 +6,7 @@ using System.Reflection;
using System.Text;
using Verse;
using System.Text.RegularExpressions;
using WulaFallenEmpire.EventSystem.AI.UI;
using WulaFallenEmpire.EventSystem.AI;
namespace WulaFallenEmpire.EventSystem.AI.Tools
{
@@ -110,10 +110,10 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
private static string BuildToolHistory(int maxCount)
{
var window = Dialog_AIConversation.Instance ?? Find.WindowStack.WindowOfType<Dialog_AIConversation>();
if (window == null) return "AI Tool History: none found.";
var core = AIIntelligenceCore.Instance;
if (core == null) return "AI Tool History: none found.";
var history = window.GetHistorySnapshot();
var history = core.GetHistorySnapshot();
if (history == null || history.Count == 0) return "AI Tool History: none found.";
var entries = new List<(string ToolXml, string ToolResult)>();
@@ -310,3 +310,4 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -7,7 +7,6 @@ using System.Threading.Tasks;
using RimWorld;
using UnityEngine;
using Verse;
using WulaFallenEmpire.EventSystem.AI;
using WulaFallenEmpire.EventSystem.AI.Tools;
using System.Text.RegularExpressions;
@@ -45,13 +44,6 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
private const int DefaultMaxHistoryTokens = 100000;
private const int CharsPerToken = 4;
private const int ThinkingPhaseTotal = 3;
private const int MemorySearchLimit = 6;
private const int MemoryFactMaxChars = 200;
private const int MemoryPromptMaxChars = 1600;
private const int MemoryUpdateMaxMemories = 40;
private string _memoryContextCache = "";
private string _memoryContextQuery = "";
private bool _memoryExtractionInFlight = false;
private enum RequestPhase
{
@@ -67,20 +59,6 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
public bool AnyActionError;
}
private struct MemoryFact
{
public string Text;
public string Category;
}
private struct MemoryUpdate
{
public string Event;
public string Id;
public string Text;
public string Category;
}
private void SetThinkingPhase(int phaseIndex, bool isRetry)
{
_thinkingPhaseIndex = Math.Max(1, Math.Min(ThinkingPhaseTotal, phaseIndex));
@@ -255,15 +233,10 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
{
// Use XML persona if available, otherwise default
string persona = !string.IsNullOrEmpty(def.aiSystemInstruction) ? def.aiSystemInstruction : DefaultPersona;
string memoryContext = _memoryContextCache;
string personaWithMemory = string.IsNullOrWhiteSpace(memoryContext)
? persona
: persona + "\n\n" + memoryContext;
string fullInstruction = toolsEnabled
? (personaWithMemory + "\n" + ToolRulesInstruction + "\n" + toolsForThisPhase)
: personaWithMemory;
? (persona + "\n" + ToolRulesInstruction + "\n" + toolsForThisPhase)
: persona;
string language = LanguageDatabase.activeLanguage.FriendlyNameNative;
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
@@ -521,542 +494,6 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
return context;
}
private void PrepareMemoryContext()
{
string lastUserMessage = _history.LastOrDefault(entry => string.Equals(entry.role, "user", StringComparison.OrdinalIgnoreCase)).message;
if (string.IsNullOrWhiteSpace(lastUserMessage))
{
_memoryContextCache = "";
_memoryContextQuery = "";
return;
}
_memoryContextQuery = lastUserMessage;
_memoryContextCache = BuildMemoryContext(lastUserMessage);
}
private string BuildMemoryContext(string userQuery)
{
if (string.IsNullOrWhiteSpace(userQuery)) return "";
var memoryManager = Find.World?.GetComponent<AIMemoryManager>();
if (memoryManager == null) return "";
var memories = memoryManager.SearchMemories(userQuery, MemorySearchLimit);
if (memories == null || memories.Count == 0) return "";
StringBuilder sb = new StringBuilder();
sb.AppendLine("# MEMORY (Relevant Facts)");
foreach (var memory in memories)
{
if (memory == null || string.IsNullOrWhiteSpace(memory.Fact)) continue;
string category = string.IsNullOrWhiteSpace(memory.Category) ? "misc" : memory.Category.Trim();
string fact = TrimMemoryFact(memory.Fact, MemoryFactMaxChars);
if (string.IsNullOrWhiteSpace(fact)) continue;
sb.AppendLine($"- [{category}] {fact}");
}
return sb.ToString().TrimEnd();
}
private static string TrimMemoryFact(string fact, int maxChars)
{
if (string.IsNullOrWhiteSpace(fact)) return "";
string trimmed = fact.Trim();
if (trimmed.Length <= maxChars) return trimmed;
return trimmed.Substring(0, maxChars) + "...";
}
private string BuildMemoryExtractionConversation()
{
if (_history == null || _history.Count == 0) return "";
const int maxTurns = 6;
var lines = new List<string>();
for (int i = _history.Count - 1; i >= 0 && lines.Count < maxTurns; i--)
{
var entry = _history[i];
if (!string.Equals(entry.role, "user", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(entry.role, "assistant", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string content = entry.role == "assistant"
? ParseResponseForDisplay(entry.message)
: entry.message;
if (string.IsNullOrWhiteSpace(content)) continue;
lines.Add($"{entry.role}: {content.Trim()}");
}
lines.Reverse();
string snippet = string.Join("\n", lines);
return TrimForPrompt(snippet, MemoryPromptMaxChars);
}
private async Task ExtractAndUpdateMemoriesAsync()
{
if (_memoryExtractionInFlight) return;
_memoryExtractionInFlight = true;
try
{
var world = Find.World;
if (world == null) return;
var memoryManager = world.GetComponent<AIMemoryManager>();
if (memoryManager == null) return;
string conversation = BuildMemoryExtractionConversation();
if (string.IsNullOrWhiteSpace(conversation)) return;
var settings = WulaFallenEmpire.WulaFallenEmpireMod.settings;
if (settings == null) return;
var client = new SimpleAIClient(settings.apiKey, settings.baseUrl, settings.model);
string extractPrompt = MemoryPrompts.BuildFactExtractionPrompt(conversation);
string extractResponse = await client.GetChatCompletionAsync(extractPrompt, new List<(string role, string message)>(), maxTokens: 256, temperature: 0.2f);
if (string.IsNullOrWhiteSpace(extractResponse)) return;
List<MemoryFact> facts = ParseFactsResponse(extractResponse);
if (facts.Count == 0) return;
var existing = memoryManager.GetAllMemories()
.OrderByDescending(m => m.UpdatedTicks)
.ThenByDescending(m => m.CreatedTicks)
.Take(MemoryUpdateMaxMemories)
.ToList();
if (existing.Count == 0)
{
AddFactsToMemory(memoryManager, facts);
return;
}
string existingJson = BuildMemoriesJson(existing);
string factsJson = BuildFactsJson(facts);
string updatePrompt = MemoryPrompts.BuildMemoryUpdatePrompt(existingJson, factsJson);
string updateResponse = await client.GetChatCompletionAsync(updatePrompt, new List<(string role, string message)>(), maxTokens: 256, temperature: 0.2f);
if (string.IsNullOrWhiteSpace(updateResponse))
{
AddFactsToMemory(memoryManager, facts);
return;
}
List<MemoryUpdate> updates = ParseMemoryUpdateResponse(updateResponse);
if (updates.Count == 0)
{
AddFactsToMemory(memoryManager, facts);
return;
}
ApplyMemoryUpdates(memoryManager, updates, facts);
}
catch (Exception ex)
{
WulaLog.Debug($"[WulaAI] Memory extraction failed: {ex}");
}
finally
{
_memoryExtractionInFlight = false;
}
}
private static void AddFactsToMemory(AIMemoryManager memoryManager, List<MemoryFact> facts)
{
if (memoryManager == null || facts == null) return;
foreach (var fact in facts)
{
if (string.IsNullOrWhiteSpace(fact.Text)) continue;
memoryManager.AddMemory(fact.Text, fact.Category);
}
}
private static void ApplyMemoryUpdates(AIMemoryManager memoryManager, List<MemoryUpdate> updates, List<MemoryFact> fallbackFacts)
{
if (memoryManager == null || updates == null) return;
bool applied = false;
bool anyDecision = false;
foreach (var update in updates)
{
if (string.IsNullOrWhiteSpace(update.Event)) continue;
switch (update.Event.Trim().ToUpperInvariant())
{
case "ADD":
anyDecision = true;
if (!string.IsNullOrWhiteSpace(update.Text))
{
memoryManager.AddMemory(update.Text, update.Category);
applied = true;
}
break;
case "UPDATE":
anyDecision = true;
if (!string.IsNullOrWhiteSpace(update.Id))
{
if (memoryManager.UpdateMemory(update.Id, update.Text, update.Category))
{
applied = true;
}
else if (!string.IsNullOrWhiteSpace(update.Text))
{
memoryManager.AddMemory(update.Text, update.Category);
applied = true;
}
}
else if (!string.IsNullOrWhiteSpace(update.Text))
{
memoryManager.AddMemory(update.Text, update.Category);
applied = true;
}
break;
case "DELETE":
anyDecision = true;
if (!string.IsNullOrWhiteSpace(update.Id) && memoryManager.DeleteMemory(update.Id))
{
applied = true;
}
break;
case "NONE":
anyDecision = true;
break;
}
}
if (!applied && !anyDecision)
{
AddFactsToMemory(memoryManager, fallbackFacts);
}
}
private static string BuildMemoriesJson(List<AIMemoryEntry> memories)
{
if (memories == null || memories.Count == 0) return "[]";
StringBuilder sb = new StringBuilder();
sb.Append("[");
bool first = true;
foreach (var memory in memories)
{
if (memory == null || string.IsNullOrWhiteSpace(memory.Fact)) continue;
if (!first) sb.Append(",");
first = false;
sb.Append("{");
sb.Append("\"id\":\"").Append(EscapeJson(memory.Id)).Append("\",");
sb.Append("\"text\":\"").Append(EscapeJson(memory.Fact)).Append("\",");
sb.Append("\"category\":\"").Append(EscapeJson(memory.Category)).Append("\"");
sb.Append("}");
}
sb.Append("]");
return sb.ToString();
}
private static string BuildFactsJson(List<MemoryFact> facts)
{
if (facts == null || facts.Count == 0) return "[]";
StringBuilder sb = new StringBuilder();
sb.Append("[");
bool first = true;
foreach (var fact in facts)
{
if (string.IsNullOrWhiteSpace(fact.Text)) continue;
if (!first) sb.Append(",");
first = false;
sb.Append("{");
sb.Append("\"text\":\"").Append(EscapeJson(fact.Text)).Append("\",");
sb.Append("\"category\":\"").Append(EscapeJson(fact.Category)).Append("\"");
sb.Append("}");
}
sb.Append("]");
return sb.ToString();
}
private static List<MemoryFact> ParseFactsResponse(string response)
{
var facts = new List<MemoryFact>();
string array = TryExtractJsonArray(response, "facts");
if (string.IsNullOrWhiteSpace(array)) return facts;
var objects = ExtractJsonObjects(array);
if (objects.Count > 0)
{
foreach (string obj in objects)
{
var dict = SimpleJsonParser.Parse(obj);
if (dict == null || dict.Count == 0) continue;
string text = GetDictionaryValue(dict, "text") ?? GetDictionaryValue(dict, "fact");
if (string.IsNullOrWhiteSpace(text)) continue;
string category = NormalizeMemoryCategory(GetDictionaryValue(dict, "category"));
facts.Add(new MemoryFact { Text = text.Trim(), Category = category });
}
}
else
{
foreach (string item in SplitJsonArrayValues(array))
{
if (string.IsNullOrWhiteSpace(item)) continue;
facts.Add(new MemoryFact { Text = item.Trim(), Category = "misc" });
}
}
var deduped = new List<MemoryFact>();
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var fact in facts)
{
string hash = AIMemoryEntry.ComputeHash(fact.Text);
if (string.IsNullOrWhiteSpace(hash) || !seen.Add(hash)) continue;
deduped.Add(fact);
}
return deduped;
}
private static List<MemoryUpdate> ParseMemoryUpdateResponse(string response)
{
var updates = new List<MemoryUpdate>();
string array = TryExtractJsonArray(response, "memory") ?? TryExtractJsonArray(response, "memories");
if (string.IsNullOrWhiteSpace(array)) return updates;
foreach (string obj in ExtractJsonObjects(array))
{
var dict = SimpleJsonParser.Parse(obj);
if (dict == null || dict.Count == 0) continue;
string evt = GetDictionaryValue(dict, "event") ?? GetDictionaryValue(dict, "action");
if (string.IsNullOrWhiteSpace(evt)) continue;
updates.Add(new MemoryUpdate
{
Event = evt.Trim().ToUpperInvariant(),
Id = GetDictionaryValue(dict, "id"),
Text = GetDictionaryValue(dict, "text") ?? GetDictionaryValue(dict, "fact"),
Category = NormalizeMemoryCategory(GetDictionaryValue(dict, "category"))
});
}
return updates;
}
private static string NormalizeMemoryCategory(string category)
{
if (string.IsNullOrWhiteSpace(category)) return "misc";
string normalized = category.Trim().ToLowerInvariant();
switch (normalized)
{
case "preference":
case "personal":
case "plan":
case "colony":
case "misc":
return normalized;
default:
return "misc";
}
}
private static string TryExtractJsonArray(string json, string key)
{
if (string.IsNullOrWhiteSpace(json) || string.IsNullOrWhiteSpace(key)) return null;
string keyPattern = $"\"{key}\"";
int keyIndex = json.IndexOf(keyPattern, StringComparison.OrdinalIgnoreCase);
if (keyIndex == -1) return null;
int arrayStart = json.IndexOf('[', keyIndex);
if (arrayStart == -1) return null;
int arrayEnd = FindMatchingBracket(json, arrayStart);
if (arrayEnd == -1) return null;
return json.Substring(arrayStart + 1, arrayEnd - arrayStart - 1);
}
private static List<string> ExtractJsonObjects(string arrayContent)
{
var objects = new List<string>();
if (string.IsNullOrWhiteSpace(arrayContent)) return objects;
int depth = 0;
int start = -1;
bool inString = false;
bool escaped = false;
for (int i = 0; i < arrayContent.Length; i++)
{
char c = arrayContent[i];
if (inString)
{
if (escaped)
{
escaped = false;
continue;
}
if (c == '\\')
{
escaped = true;
continue;
}
if (c == '"')
{
inString = false;
}
continue;
}
if (c == '"')
{
inString = true;
continue;
}
if (c == '{')
{
if (depth == 0) start = i;
depth++;
continue;
}
if (c == '}')
{
depth--;
if (depth == 0 && start >= 0)
{
objects.Add(arrayContent.Substring(start, i - start + 1));
start = -1;
}
}
}
return objects;
}
private static List<string> SplitJsonArrayValues(string arrayContent)
{
var items = new List<string>();
if (string.IsNullOrWhiteSpace(arrayContent)) return items;
bool inString = false;
bool escaped = false;
int start = 0;
for (int i = 0; i < arrayContent.Length; i++)
{
char c = arrayContent[i];
if (inString)
{
if (escaped)
{
escaped = false;
}
else if (c == '\\')
{
escaped = true;
}
else if (c == '"')
{
inString = false;
}
continue;
}
if (c == '"')
{
inString = true;
continue;
}
if (c == ',')
{
string part = arrayContent.Substring(start, i - start);
items.Add(UnescapeJsonString(part.Trim().Trim('"')));
start = i + 1;
}
}
if (start < arrayContent.Length)
{
string part = arrayContent.Substring(start);
items.Add(UnescapeJsonString(part.Trim().Trim('"')));
}
return items;
}
private static string UnescapeJsonString(string value)
{
if (string.IsNullOrEmpty(value)) return "";
return value.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\"", "\"").Replace("\\\\", "\\");
}
private static string GetDictionaryValue(Dictionary<string, string> dict, string key)
{
if (dict == null || string.IsNullOrWhiteSpace(key)) return null;
return dict.TryGetValue(key, out string value) ? value : null;
}
private static string EscapeJson(string value)
{
if (string.IsNullOrEmpty(value)) return "";
return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n").Replace("\r", "\\r");
}
private static int FindMatchingBracket(string json, int startIndex)
{
int depth = 0;
bool inString = false;
bool escaped = false;
for (int i = startIndex; i < json.Length; i++)
{
char c = json[i];
if (inString)
{
if (escaped)
{
escaped = false;
continue;
}
if (c == '\\')
{
escaped = true;
continue;
}
if (c == '"')
{
inString = false;
}
continue;
}
if (c == '"')
{
inString = true;
continue;
}
if (c == '[')
{
depth++;
continue;
}
if (c == ']')
{
depth--;
if (depth == 0) return i;
}
}
return -1;
}
private async Task RunPhasedRequestAsync()
{
if (_isThinking) return;
@@ -1081,7 +518,6 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
try
{
PrepareMemoryContext();
CompressHistoryIfNeeded();
var settings = WulaFallenEmpireMod.settings;
@@ -1365,7 +801,6 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
}
ParseResponse(reply);
_ = ExtractAndUpdateMemoriesAsync();
}
catch (Exception ex)
{
@@ -2082,8 +1517,6 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
_inputText = "";
_history.Clear();
_memoryContextCache = "";
_memoryContextQuery = "";
try
{
var historyManager = Find.World?.GetComponent<AIHistoryManager>();

View File

@@ -0,0 +1,549 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
using RimWorld;
using WulaFallenEmpire.EventSystem.AI;
namespace WulaFallenEmpire.EventSystem.AI.UI
{
public class Overlay_WulaLink : Window
{
// Core Connection
private AIIntelligenceCore _core;
private string _eventDefName;
private EventDef _def;
// UI State
private Vector2 _scrollPosition = Vector2.zero;
private string _inputText = "";
private bool _scrollToBottom = true;
// HUD / Minimized State
private bool _isMinimized = false;
private int _unreadCount = 0;
private Vector2 _expandedSize;
private Vector2 _minimizedSize = new Vector2(220f, 80f);
// Layout Constants
private const float HeaderHeight = 50f;
private const float FooterHeight = 50f;
private const float AvatarSize = 40f;
private const float BubblePadding = 10f;
private const float MessageSpacing = 15f;
private const float MaxBubbleWidthRatio = 0.75f;
public Overlay_WulaLink(EventDef def)
{
this._def = def;
this._eventDefName = def.defName;
// Window Properties (Floating, Non-Modal)
this.layer = WindowLayer.GameUI;
this.forcePause = false;
this.absorbInputAroundWindow = false;
this.closeOnClickedOutside = false;
this.doWindowBackground = false; // We draw our own
this.drawShadow = true;
this.draggable = true;
this.resizeable = true;
this.preventCameraMotion = false;
// Initial Size (Phone-like)
_expandedSize = new Vector2(380f, 600f);
}
public override Vector2 InitialSize => _isMinimized ? _minimizedSize : _expandedSize;
public void ToggleMinimize()
{
_isMinimized = !_isMinimized;
_unreadCount = 0; // Reset on toggle? Or only on expand? Let's say expand.
if (_isMinimized)
{
// Save current position if needed, or just snap to right edge
windowRect.width = _minimizedSize.x;
windowRect.height = _minimizedSize.y;
windowRect.x = Verse.UI.screenWidth - _minimizedSize.x - 20f;
windowRect.y = Verse.UI.screenHeight / 2f;
}
else
{
windowRect.width = _expandedSize.x;
windowRect.height = _expandedSize.y;
}
}
public void Expand()
{
if (_isMinimized) ToggleMinimize();
// Ensure window is on screen
if (windowRect.x > Verse.UI.screenWidth - 100f)
{
windowRect.x = Verse.UI.screenWidth - _expandedSize.x - 20f;
}
Find.WindowStack.Notify_ManuallySetFocus(this);
}
public override void PreOpen()
{
base.PreOpen();
// Connect to Core
_core = Find.World.GetComponent<AIIntelligenceCore>();
if (_core != null)
{
_core.InitializeConversation(_eventDefName);
_core.OnMessageReceived += OnMessageReceived;
_core.OnThinkingStateChanged += OnThinkingStateChanged;
_core.OnExpressionChanged += OnExpressionChanged;
}
}
public override void PostClose()
{
base.PostClose();
if (_core != null)
{
_core.OnMessageReceived -= OnMessageReceived;
_core.OnThinkingStateChanged -= OnThinkingStateChanged;
_core.OnExpressionChanged -= OnExpressionChanged;
}
}
private void OnMessageReceived(string msg)
{
_scrollToBottom = true;
if (_isMinimized)
{
_unreadCount++;
// Spawn Notification Bubble
Find.WindowStack.Add(new Overlay_WulaLink_Notification(msg));
}
}
private void OnThinkingStateChanged(bool thinking)
{
// Trigger repaint or animation update if needed
}
private void OnExpressionChanged(int id)
{
// Repaint happens next frame
}
public override void DoWindowContents(Rect inRect)
{
if (_isMinimized)
{
DrawMinimized(inRect);
return;
}
// Draw Main Background (Whole Window)
Widgets.DrawBoxSolid(inRect, WulaLinkStyles.BackgroundColor);
GUI.color = new Color(0.8f, 0.8f, 0.8f);
Widgets.DrawBox(inRect, 1); // Border
GUI.color = Color.white;
// Areas
Rect headerRect = new Rect(0, 0, inRect.width, HeaderHeight);
Rect footerRect = new Rect(0, inRect.height - FooterHeight, inRect.width, FooterHeight);
Rect contextRect = new Rect(0, inRect.height - FooterHeight - 30f, inRect.width, 30f); // Context Bar
Rect bodyRect = new Rect(0, HeaderHeight, inRect.width, inRect.height - HeaderHeight - FooterHeight - 30f);
// Draw Components
DrawHeader(headerRect);
DrawMessageList(bodyRect);
DrawContextBar(contextRect);
DrawFooter(footerRect);
}
private void DrawMinimized(Rect rect)
{
// HUD Capsule Style
Widgets.DrawBoxSolid(rect, new Color(0.1f, 0.1f, 0.1f, 0.85f)); // Semi-transparent black
GUI.color = WulaLinkStyles.HeaderColor;
Widgets.DrawBox(rect, 2); // Thicker colored border
GUI.color = Color.white;
// Layout
Rect titleRect = new Rect(rect.x + 10f, rect.y + 5f, rect.width - 20f, 25f);
Rect statusRect = new Rect(rect.x + 10f, rect.yMax - 30f, rect.width - 20f, 25f);
// Title
Text.Anchor = TextAnchor.MiddleCenter;
Text.Font = GameFont.Small;
Widgets.Label(titleRect, "WULA LINK");
// Status
string status = _core.IsThinking ? "Thinking..." : "Standby";
Color statusColor = _core.IsThinking ? Color.yellow : Color.green;
GUI.color = statusColor;
Widgets.Label(statusRect, $"â—?{status}");
GUI.color = Color.white;
// Unread Badge
if (_unreadCount > 0)
{
float badgeSize = 24f;
Rect badgeRect = new Rect(rect.xMax - badgeSize - 5f, rect.y - 10f, badgeSize, badgeSize);
GUI.color = Color.red;
GUI.DrawTexture(badgeRect, BaseContent.WhiteTex); // Circle ideally
GUI.color = Color.white;
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
Widgets.Label(badgeRect, _unreadCount.ToString());
Text.Font = GameFont.Small;
}
Text.Anchor = TextAnchor.UpperLeft;
// Click to Expand
if (Widgets.ButtonInvisible(rect))
{
ToggleMinimize();
}
}
private void DrawContextBar(Rect rect)
{
// Context Awareness
Widgets.DrawBoxSolid(rect, new Color(0.15f, 0.15f, 0.15f, 1f));
GUI.color = Color.grey;
Widgets.DrawLineHorizontal(rect.x, rect.y, rect.width);
string contextInfo = "Context: None";
if (Find.Selector.SingleSelectedThing != null)
{
contextInfo = $"Context: [{Find.Selector.SingleSelectedThing.LabelCap}]";
}
else if (Find.Selector.SelectedObjects.Count > 1)
{
contextInfo = $"Context: {Find.Selector.SelectedObjects.Count} objects selected";
}
Text.Anchor = TextAnchor.MiddleLeft;
Text.Font = GameFont.Tiny;
Widgets.Label(new Rect(rect.x + 10f, rect.y, rect.width - 20f, rect.height), contextInfo);
Text.Anchor = TextAnchor.UpperLeft;
GUI.color = Color.white;
}
private void DrawHeader(Rect rect)
{
// Header BG
Widgets.DrawBoxSolid(rect, WulaLinkStyles.HeaderColor);
// Title
Text.Font = GameFont.Medium;
Text.Anchor = TextAnchor.MiddleLeft;
GUI.color = Color.white;
Rect titleRect = rect;
titleRect.x += 10f;
Widgets.Label(titleRect, _def.characterName ?? "MomoTalk");
// Header Icons (Minimize/Close)
Rect closeRect = new Rect(rect.width - 30f, 10f, 20f, 20f);
Rect minRect = new Rect(rect.width - 60f, 10f, 20f, 20f);
if (Widgets.ButtonText(minRect, "-"))
{
ToggleMinimize();
}
if (Widgets.ButtonImage(closeRect, Widgets.CheckboxOffTex)) // Use standard X tex
{
Close();
}
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
}
private void DrawMessageList(Rect rect)
{
var history = _core?.GetHistorySnapshot();
if (history == null) return;
// Filter out tool messages for cleaner display (only show in DevMode)
var displayHistory = new List<(string role, string message)>();
foreach (var msg in history)
{
// Skip tool/toolcall messages entirely in normal mode
if ((msg.role == "tool" || msg.role == "toolcall") && !Prefs.DevMode) continue;
displayHistory.Add(msg);
}
// Setup ScrollView
float contentHeight = 0f;
float width = rect.width - 26f; // Scrollbar space (16 + margin)
float reducedSpacing = 8f; // Reduced from MessageSpacing (15f) to 8f
List<float> heights = new List<float>();
foreach (var msg in displayHistory)
{
float h = CalcMessageHeight(msg.message, width);
heights.Add(h);
contentHeight += h + reducedSpacing;
}
if (_core.IsThinking)
{
contentHeight += 40f; // Space for thinking indicator
}
Rect viewRect = new Rect(0, 0, width, contentHeight);
// Handle Auto Scroll
if (_scrollToBottom)
{
_scrollPosition.y = contentHeight - rect.height;
_scrollToBottom = false;
}
Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect);
float curY = 10f;
for (int i = 0; i < displayHistory.Count; i++)
{
var entry = displayHistory[i];
float h = heights[i];
Rect msgRect = new Rect(0, curY, width, h);
if (entry.role == "user")
{
DrawSenseiMessage(msgRect, entry.message);
}
else if (entry.role == "assistant")
{
DrawStudentMessage(msgRect, entry.message);
}
else if (entry.role == "tool" || entry.role == "toolcall")
{
// Only shown in DevMode (already filtered above)
DrawSystemMessage(msgRect, $"[Tool] {entry.message}");
}
else if (entry.role == "system")
{
DrawSystemMessage(msgRect, entry.message);
}
curY += h + reducedSpacing;
}
if (_core.IsThinking)
{
Rect thinkingRect = new Rect(0, curY, width, 30f);
DrawThinkingIndicator(thinkingRect);
}
Widgets.EndScrollView();
}
private void DrawFooter(Rect rect)
{
Widgets.DrawBoxSolid(rect, WulaLinkStyles.InputBarColor);
Widgets.DrawLineHorizontal(rect.x, rect.y, rect.width); // Top border
float padding = 8f;
float btnWidth = 40f;
float inputWidth = rect.width - btnWidth - (padding * 3);
Rect inputRect = new Rect(rect.x + padding, rect.y + padding, inputWidth, rect.height - (padding * 2));
Rect btnRect = new Rect(inputRect.xMax + padding, rect.y + padding, btnWidth, rect.height - (padding * 2));
// Input Field
string nextInput = Widgets.TextField(inputRect, _inputText);
if (nextInput != _inputText)
{
_inputText = nextInput;
}
// Send Button (Simulate Enter key or Click)
bool enterPressed = (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter) && GUI.GetNameOfFocusedControl() == "WulaInput");
bool sendClicked = DrawCustomButton(btnRect, ">", !string.IsNullOrWhiteSpace(_inputText));
if (sendClicked || enterPressed)
{
if (!string.IsNullOrWhiteSpace(_inputText))
{
bool wasFocused = GUI.GetNameOfFocusedControl() == "WulaInput";
_core.SendUserMessage(_inputText);
_inputText = "";
if (wasFocused) GUI.FocusControl("WulaInput");
}
}
// Handle focus for Enter key to work
if (Mouse.IsOver(inputRect) && Event.current.type == EventType.MouseDown)
{
GUI.FocusControl("WulaInput");
}
GUI.SetNextControlName("WulaInput");
}
// =================================================================================
// Message Rendering Helpers
// =================================================================================
private float CalcMessageHeight(string text, float containerWidth)
{
float maxBubbleWidth = containerWidth * MaxBubbleWidthRatio;
Text.Font = WulaLinkStyles.MessageFont;
float textH = Text.CalcHeight(text, maxBubbleWidth - (BubblePadding * 2));
return Mathf.Max(textH + (BubblePadding * 2), AvatarSize);
}
private void DrawSenseiMessage(Rect rect, string text)
{
// Right aligned Blue Bubble
float maxBubbleWidth = rect.width * MaxBubbleWidthRatio;
Text.Font = WulaLinkStyles.MessageFont;
Vector2 textSize = Text.CalcSize(text);
float bubbleWidth = Mathf.Min(textSize.x + (BubblePadding * 2), maxBubbleWidth);
float bubbleHeight = rect.height;
Rect bubbleRect = new Rect(rect.xMax - bubbleWidth - 10f, rect.y, bubbleWidth, bubbleHeight);
// Draw Bubble
GUI.color = WulaLinkStyles.SenseiBubbleColor;
Widgets.DrawBoxSolid(bubbleRect, WulaLinkStyles.SenseiBubbleColor); // Rounded rect ideally
GUI.color = Color.white;
// Text
Rect textRect = bubbleRect.ContractedBy(BubblePadding);
GUI.color = WulaLinkStyles.SenseiTextColor;
Text.Anchor = TextAnchor.MiddleLeft;
Widgets.Label(textRect, text);
Text.Anchor = TextAnchor.UpperLeft;
GUI.color = Color.white;
}
private void DrawStudentMessage(Rect rect, string text)
{
// Left aligned White Bubble + Avatar
float avatarX = 10f;
Rect avatarRect = new Rect(avatarX, rect.y, AvatarSize, AvatarSize);
// Avatar
int expId = _core?.ExpressionId ?? 1;
string portraitPath = _def.portraitPath ?? $"Wula/Events/Portraits/WULA_Legion_{expId}";
if (expId > 1 && _def.portraitPath == null) // If using default Legion set
{
portraitPath = $"Wula/Events/Portraits/WULA_Legion_{expId}";
}
Texture2D portrait = ContentFinder<Texture2D>.Get(portraitPath, false);
if (portrait != null)
{
GUI.DrawTexture(avatarRect, portrait); // Needs circle mask ideally
}
else
{
Widgets.DrawBoxSolid(avatarRect, Color.gray);
}
float maxBubbleWidth = rect.width * MaxBubbleWidthRatio;
float bubbleX = avatarRect.xMax + 10f;
Text.Font = WulaLinkStyles.MessageFont;
Vector2 textSize = Text.CalcSize(text);
float bubbleWidth = Mathf.Min(textSize.x + (BubblePadding * 2), maxBubbleWidth);
float bubbleHeight = rect.height; // Height was pre-calculated
Rect bubbleRect = new Rect(bubbleX, rect.y, bubbleWidth, bubbleHeight);
// Draw Bubble
GUI.color = WulaLinkStyles.StudentStrokeColor;
Widgets.DrawBox(bubbleRect, 1);
GUI.color = WulaLinkStyles.StudentBubbleColor;
Widgets.DrawBoxSolid(bubbleRect, WulaLinkStyles.StudentBubbleColor);
GUI.color = Color.white;
// Text
Rect textRect = bubbleRect.ContractedBy(BubblePadding);
GUI.color = WulaLinkStyles.StudentTextColor;
Text.Anchor = TextAnchor.MiddleLeft;
Widgets.Label(textRect, text);
Text.Anchor = TextAnchor.UpperLeft;
GUI.color = Color.white;
}
private void DrawSystemMessage(Rect rect, string text)
{
// Centered gray text or Pink box
if (text.Contains("[Tool]")) return; // Skip logic log in main view if needed, but here we draw minimal
GUI.color = Color.gray;
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.MiddleCenter;
Widgets.Label(rect, text);
Text.Anchor = TextAnchor.UpperLeft;
GUI.color = Color.white;
}
private void DrawThinkingIndicator(Rect rect)
{
Text.Anchor = TextAnchor.MiddleLeft;
GUI.color = Color.gray;
Rect iconRect = new Rect(rect.x + 60f, rect.y, 24f, 24f);
Rect labelRect = new Rect(iconRect.xMax + 5f, rect.y, 200f, 24f);
// Draw a simple box as thinking indicator if TexUI is missing
Widgets.DrawBoxSolid(iconRect, Color.gray);
Widgets.Label(labelRect, "P.I.A is thinking...");
Text.Anchor = TextAnchor.UpperLeft;
GUI.color = Color.white;
}
private bool DrawCustomButton(Rect rect, string label, bool isEnabled)
{
bool isMouseOver = Mouse.IsOver(rect);
Color originalColor = GUI.color;
TextAnchor originalAnchor = Text.Anchor;
GameFont originalFont = Text.Font;
Color buttonColor;
Color textColor;
if (!isEnabled)
{
buttonColor = Dialog_CustomDisplay.CustomButtonDisabledColor;
textColor = Dialog_CustomDisplay.CustomButtonTextDisabledColor;
}
else if (isMouseOver)
{
buttonColor = Dialog_CustomDisplay.CustomButtonHoverColor;
textColor = Dialog_CustomDisplay.CustomButtonTextHoverColor;
}
else
{
buttonColor = Dialog_CustomDisplay.CustomButtonNormalColor;
textColor = Dialog_CustomDisplay.CustomButtonTextNormalColor;
}
GUI.color = buttonColor;
Widgets.DrawBoxSolid(rect, buttonColor);
Widgets.DrawBox(rect, 1);
GUI.color = textColor;
Text.Anchor = TextAnchor.MiddleCenter;
Text.Font = GameFont.Tiny;
Widgets.Label(rect.ContractedBy(4f), label);
GUI.color = originalColor;
Text.Anchor = originalAnchor;
Text.Font = originalFont;
if (!isEnabled)
{
return false;
}
return Widgets.ButtonInvisible(rect);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using UnityEngine;
using Verse;
using RimWorld;
using WulaFallenEmpire.EventSystem.AI;
namespace WulaFallenEmpire.EventSystem.AI.UI
{
public class Overlay_WulaLink_Notification : Window
{
private string _message;
private int _tickCreated;
private const int DisplayTicks = 300; // 5 seconds
public override Vector2 InitialSize => new Vector2(300f, 80f);
public Overlay_WulaLink_Notification(string message)
{
_message = message;
_tickCreated = Find.TickManager.TicksGame;
// Transient properties
this.layer = WindowLayer.Super; // Topmost
this.closeOnClickedOutside = false;
this.forcePause = false;
this.absorbInputAroundWindow = false;
this.doWindowBackground = false; // Custom bg
this.drawShadow = false;
}
public override void DoWindowContents(Rect inRect)
{
// Auto Close after time
if (Find.TickManager.TicksGame > _tickCreated + DisplayTicks)
{
Close();
return;
}
// Draw HUD Notification Style
Widgets.DrawBoxSolid(inRect, new Color(0.1f, 0.1f, 0.1f, 0.9f));
GUI.color = WulaLinkStyles.SystemAccentColor;
Widgets.DrawBox(inRect, 1);
GUI.color = Color.white;
Rect iconRect = new Rect(10f, 10f, 30f, 30f);
Rect titleRect = new Rect(50f, 10f, 200f, 20f);
Rect textRect = new Rect(50f, 30f, 240f, 40f);
// Icon (Warning / Info)
Widgets.DrawBoxSolid(iconRect, WulaLinkStyles.SystemAccentColor);
GUI.color = Color.black;
Text.Anchor = TextAnchor.MiddleCenter;
Text.Font = GameFont.Medium;
Widgets.Label(iconRect, "!");
GUI.color = Color.white;
// Title
Text.Anchor = TextAnchor.UpperLeft;
Text.Font = GameFont.Tiny;
GUI.color = Color.yellow;
Widgets.Label(titleRect, "WULA LINK :: NEW ALERT");
GUI.color = Color.white;
// Text
Text.Font = GameFont.Small;
string truncated = _message.Length > 40 ? _message.Substring(0, 38) + "..." : _message;
Widgets.Label(textRect, truncated);
// Click to Open/Expand
if (Widgets.ButtonInvisible(inRect))
{
OpenWulaLink();
Close();
}
}
public void OpenWulaLink()
{
// Find existing or open new
var existing = Find.WindowStack.WindowOfType<Overlay_WulaLink>();
if (existing != null)
{
existing.Expand();
Find.WindowStack.Notify_ManuallySetFocus(existing);
}
else
{
// Create new if not exists
var core = AIIntelligenceCore.Instance;
// Without EventDef we can't easily open.
// Assuming notification implies active core state.
}
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using UnityEngine;
using Verse;
namespace WulaFallenEmpire.EventSystem.AI.UI
{
[StaticConstructorOnStartup]
public static class WulaLinkStyles
{
// =================================================================================
// Colors
// =================================================================================
// Background Colors - Semi-transparent red theme
public static readonly Color BackgroundColor = new Color(0.2f, 0.05f, 0.05f, 0.85f);
public static readonly Color HeaderColor = new Color(0.5f, 0.2f, 0.2f, 1f);
public static readonly Color InputBarColor = new Color(0.16f, 0.08f, 0.08f, 0.95f);
public static readonly Color SystemAccentColor = new Color(0.6f, 0.2f, 0.2f, 1f);
// Message Bubble Colors - Matching Dialog_CustomDisplay button style
public static readonly Color SenseiBubbleColor = new Color(0.5f, 0.2f, 0.2f, 1f);
public static readonly Color StudentBubbleColor = new Color(0.15f, 0.15f, 0.2f, 0.9f);
public static readonly Color StudentStrokeColor = new Color(0.6f, 0.3f, 0.3f, 1f);
// Text Colors
public static readonly Color TextColor = new Color32(220, 220, 220, 255);
public static readonly Color SenseiTextColor = new Color32(240, 240, 240, 255);
public static readonly Color StudentTextColor = new Color32(230, 230, 230, 255);
public static readonly Color InputBorderColor = new Color32(60, 60, 60, 255);
// =================================================================================
// Fonts
// =================================================================================
public static GameFont MessageFont = GameFont.Small;
public static GameFont HeaderFont = GameFont.Medium;
// =================================================================================
// Textures
// =================================================================================
public static readonly Texture2D TexCircleMask;
public static readonly Texture2D TexSendIcon;
public static readonly Texture2D TexPaperClip;
public static readonly Texture2D TexWhite;
static WulaLinkStyles()
{
TexCircleMask = ContentFinder<Texture2D>.Get("Base/UI/WulaLink/CircleMask", false);
TexSendIcon = ContentFinder<Texture2D>.Get("Base/UI/WulaLink/Send", false);
TexPaperClip = ContentFinder<Texture2D>.Get("Base/UI/WulaLink/Clip", false);
TexWhite = SolidColorMaterials.NewSolidColorTexture(Color.white);
}
}
}

View File

@@ -22,7 +22,16 @@ namespace WulaFallenEmpire
EventDef eventDef = DefDatabase<EventDef>.GetNamed(defName, false);
if (eventDef != null)
{
Find.WindowStack.Add(new Dialog_AIConversation(eventDef));
var existing = Find.WindowStack.WindowOfType<Overlay_WulaLink>();
if (existing != null)
{
existing.Expand();
Find.WindowStack.Notify_ManuallySetFocus(existing);
}
else
{
Find.WindowStack.Add(new Overlay_WulaLink(eventDef));
}
}
else
{
@@ -30,4 +39,4 @@ namespace WulaFallenEmpire
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
?????????????????
??????????????????????????????????
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(69,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenWidth????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(70,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenHeight????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(83,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenWidth????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(85,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenWidth????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(87,13): error CS0103: ???????????????????ringToFront??[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(334,50): warning CS1998: ???????????"await" ??????????????????????????? "await" ??????????????API ???????????"await Task.Run(...)" ?????????????????? CPU ???????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(98,24): warning CS0414: ?????IIntelligenceCore._memoryContextQuery???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(90,22): warning CS0414: ?????IIntelligenceCore._actionRetryUsed???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Dialog_AIConversation.cs(20,21): warning CS0414: ?????ialog_AIConversation._currentPortraitId???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(21,23): warning CS0414: ?????verlay_WulaLink._lastMessageHeight???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
????????
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(334,50): warning CS1998: ???????????"await" ??????????????????????????? "await" ??????????????API ???????????"await Task.Run(...)" ?????????????????? CPU ???????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(98,24): warning CS0414: ?????IIntelligenceCore._memoryContextQuery???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(90,22): warning CS0414: ?????IIntelligenceCore._actionRetryUsed???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Dialog_AIConversation.cs(20,21): warning CS0414: ?????ialog_AIConversation._currentPortraitId???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(21,23): warning CS0414: ?????verlay_WulaLink._lastMessageHeight???????????????????????[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(69,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenWidth????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(70,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenHeight????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(83,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenWidth????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(85,32): error CS0234: ????????ulaFallenEmpire.EventSystem.AI.UI??????????????????????creenWidth????????????????) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(87,13): error CS0103: ???????????????????ringToFront??[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
5 ?????
5 ?????
?????? 00:00:00.41

Binary file not shown.

View File

@@ -0,0 +1,23 @@
姝e湪纭畾瑕佽繕鍘熺殑椤圭洰鈥?
鏃犲彲鎵ц鎿嶄綔銆傛寚瀹氱殑椤圭洰鍧囦笉鍖呭惈鍙繕鍘熺殑鍖呫€?
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(323,50): warning CS1998: 姝ゅ紓姝ユ柟娉曠己灏?"await" 杩愮畻绗︼紝灏嗕互鍚屾鏂瑰紡杩愯銆傝鑰冭檻浣跨敤 "await" 杩愮畻绗︾瓑寰呴潪闃绘鐨?API 璋冪敤锛屾垨鑰呬娇鐢?"await Task.Run(...)" 鍦ㄥ悗鍙扮嚎绋嬩笂鎵ц鍗犵敤澶ч噺 CPU 鐨勫伐浣溿€?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\Tools\Tool_GetRecentNotifications.cs(116,34): error CS1061: 鈥淒ialog_AIConversation鈥濇湭鍖呭惈鈥淕etHistorySnapshot鈥濈殑瀹氫箟锛屽苟涓旀壘涓嶅埌鍙帴鍙楃涓€涓€淒ialog_AIConversation鈥濈被鍨嬪弬鏁扮殑鍙闂墿灞曟柟娉曗€淕etHistorySnapshot鈥?鏄惁缂哄皯 using 鎸囦护鎴栫▼搴忛泦寮曠敤?) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\Tools\Tool_GetRecentNotifications.cs(117,36): error CS0019: 杩愮畻绗︹€?=鈥濇棤娉曞簲鐢ㄤ簬鈥滄柟娉曠粍鈥濆拰鈥渋nt鈥濈被鍨嬬殑鎿嶄綔鏁?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\Tools\Tool_GetRecentNotifications.cs(120,26): error CS0019: 杩愮畻绗︹€?鈥濇棤娉曞簲鐢ㄤ簬鈥滄柟娉曠粍鈥濆拰鈥渋nt鈥濈被鍨嬬殑鎿嶄綔鏁?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(21,23): warning CS0414: 瀛楁鈥淥verlay_WulaLink._lastMessageHeight鈥濆凡琚祴鍊硷紝浣嗕粠鏈娇鐢ㄨ繃瀹冪殑鍊?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(79,22): warning CS0414: 瀛楁鈥淎IIntelligenceCore._actionRetryUsed鈥濆凡琚祴鍊硷紝浣嗕粠鏈娇鐢ㄨ繃瀹冪殑鍊?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(87,24): warning CS0414: 瀛楁鈥淎IIntelligenceCore._memoryContextQuery鈥濆凡琚祴鍊硷紝浣嗕粠鏈娇鐢ㄨ繃瀹冪殑鍊?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
鐢熸垚澶辫触銆?
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(323,50): warning CS1998: 姝ゅ紓姝ユ柟娉曠己灏?"await" 杩愮畻绗︼紝灏嗕互鍚屾鏂瑰紡杩愯銆傝鑰冭檻浣跨敤 "await" 杩愮畻绗︾瓑寰呴潪闃绘鐨?API 璋冪敤锛屾垨鑰呬娇鐢?"await Task.Run(...)" 鍦ㄥ悗鍙扮嚎绋嬩笂鎵ц鍗犵敤澶ч噺 CPU 鐨勫伐浣溿€?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs(21,23): warning CS0414: 瀛楁鈥淥verlay_WulaLink._lastMessageHeight鈥濆凡琚祴鍊硷紝浣嗕粠鏈娇鐢ㄨ繃瀹冪殑鍊?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(79,22): warning CS0414: 瀛楁鈥淎IIntelligenceCore._actionRetryUsed鈥濆凡琚祴鍊硷紝浣嗕粠鏈娇鐢ㄨ繃瀹冪殑鍊?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs(87,24): warning CS0414: 瀛楁鈥淎IIntelligenceCore._memoryContextQuery鈥濆凡琚祴鍊硷紝浣嗕粠鏈娇鐢ㄨ繃瀹冪殑鍊?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\Tools\Tool_GetRecentNotifications.cs(116,34): error CS1061: 鈥淒ialog_AIConversation鈥濇湭鍖呭惈鈥淕etHistorySnapshot鈥濈殑瀹氫箟锛屽苟涓旀壘涓嶅埌鍙帴鍙楃涓€涓€淒ialog_AIConversation鈥濈被鍨嬪弬鏁扮殑鍙闂墿灞曟柟娉曗€淕etHistorySnapshot鈥?鏄惁缂哄皯 using 鎸囦护鎴栫▼搴忛泦寮曠敤?) [C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\Tools\Tool_GetRecentNotifications.cs(117,36): error CS0019: 杩愮畻绗︹€?=鈥濇棤娉曞簲鐢ㄤ簬鈥滄柟娉曠粍鈥濆拰鈥渋nt鈥濈被鍨嬬殑鎿嶄綔鏁?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\Tools\Tool_GetRecentNotifications.cs(120,26): error CS0019: 杩愮畻绗︹€?鈥濇棤娉曞簲鐢ㄤ簬鈥滄柟娉曠粍鈥濆拰鈥渋nt鈥濈被鍨嬬殑鎿嶄綔鏁?[C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj]
4 涓鍛?
3 涓敊璇?
宸茬敤鏃堕棿 00:00:00.48