zc
This commit is contained in:
1235
Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs
Normal file
1235
Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
549
Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs
Normal file
549
Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Source/WulaFallenEmpire/EventSystem/AI/UI/WulaLinkStyles.cs
Normal file
53
Source/WulaFallenEmpire/EventSystem/AI/UI/WulaLinkStyles.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
Source/WulaFallenEmpire/build_log.txt
Normal file
29
Source/WulaFallenEmpire/build_log.txt
Normal 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
|
||||
BIN
Source/WulaFallenEmpire/build_output.txt
Normal file
BIN
Source/WulaFallenEmpire/build_output.txt
Normal file
Binary file not shown.
23
Source/WulaFallenEmpire/trace.txt
Normal file
23
Source/WulaFallenEmpire/trace.txt
Normal 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
|
||||
Reference in New Issue
Block a user