Decompiled source of IcarusII v0.3.1
plugins/IcarusII/IcarusII.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net.WebSockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using IcarusII.Common.Json; using IcarusII.Common.Protocol; using IcarusII.Common.Transport; using IcarusII.Config; using IcarusII.Core; using IcarusII.Game; using IcarusII.Game.Tools; using IcarusII.I18n; using IcarusII.Input; using IcarusII.UI; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; using UnityEngine.UI.Youthcat; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("IcarusII")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.1.0")] [assembly: AssemblyInformationalVersion("0.3.1+1b7f2ec5d444f7a0ac182445dfdb829e51de39b7")] [assembly: AssemblyProduct("IcarusII")] [assembly: AssemblyTitle("IcarusII")] [assembly: AssemblyVersion("0.3.1.0")] namespace IcarusII { [BepInPlugin("icarus-ii", "Icarus II", "0.3.1")] [BepInProcess("DSPGAME.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "icarus-ii"; public const string PluginName = "Icarus II"; public const string PluginVersion = "0.3.1"; private const int MainThreadBudgetMs = 4; private static readonly Color AccentColor = new Color(0.353f, 0.749f, 1f, 1f); private static readonly Color OkColor = new Color(0.45f, 0.85f, 0.55f); private static readonly Color WarnColor = new Color(0.95f, 0.75f, 0.35f); private PluginConfig _config; private MainThreadDispatcher _dispatcher; private SidecarLauncher _launcher; private SidecarClient _client; private HotkeyService _hotkey; private ChatWindow _chat; private GameToolDispatcher _tools; private string _pluginDir; private bool _uiInitialized; private bool _streaming; private string _pendingHint; private volatile bool _sidecarStartAttempted; private bool _uiCreateFailureLogged; private bool _styleApplied; private bool _initFailed; private ConfigState _lastConfig; private bool _thinkingLevelDirty; private string _lastFinalReplyTo; private readonly Dictionary<string, string> _promptById = new Dictionary<string, string>(StringComparer.Ordinal); private readonly Dictionary<string, string> _regenerateDeleteId = new Dictionary<string, string>(StringComparer.Ordinal); private string _saveKey; private readonly HashSet<string> _internalCalls = new HashSet<string>(StringComparer.Ordinal); private bool _saveSynced; private string _historyReplayedFor; private bool _welcomeShown; private bool _styleCaptured; private int _styleWaitFrames; private const int StyleWaitFramesBeforeFallback = 360; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0180: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; try { _config = new PluginConfig(((BaseUnityPlugin)this).Config); _dispatcher = new MainThreadDispatcher(); _tools = new GameToolDispatcher(Log); _hotkey = new HotkeyService(_config); _chat = new ChatWindow(); _chat.Submitted += OnUserSubmitted; _chat.KeySubmitted += OnKeySubmitted; _chat.ThinkingLevelChanged += OnThinkingLevelChanged; _chat.ModelSelectionChanged += OnModelSelectionChanged; _chat.TurnDeleted += OnTurnDeleted; _chat.RegenerateRequested += OnRegenerateRequested; _chat.BlueprintCardActionRequested += OnBlueprintCardAction; _pluginDir = ResolvePluginDir(); _launcher = new SidecarLauncher(_config, Log, _pluginDir); } catch (Exception arg) { _initFailed = true; ((BaseUnityPlugin)this).Logger.LogError((object)$"初始化失败,插件将不可用:{arg}"); return; } Log.LogInfo((object)"Icarus II 0.3.1 已加载"); Log.LogInfo((object)("插件目录:" + _pluginDir)); Log.LogInfo((object)$"热键:{_config.Hotkey}(建造模式让位 = {_config.HotkeyRequireNoBuildTool})"); Log.LogInfo((object)$"sidecar:{_config.LaunchMode} @ {_config.SidecarHost}:{_config.SidecarPort}"); Log.LogInfo((object)("数据目录:" + _launcher.DataDir)); Task.Run((Action)PrepareSidecar); } private void Update() { //IL_021a: Unknown result type (might be due to invalid IL or missing references) ModelSettingsTab.Watch(); if (_initFailed) { return; } _dispatcher.Drain(4, delegate(Exception ex) { Log.LogError((object)$"主线程任务异常:{ex}"); }); SyncSaveBinding(); _tools.Tick(2, OnToolDone); if (_uiInitialized && !_chat.Alive) { _uiInitialized = false; _streaming = false; _chat.Reset(); Log.LogInfo((object)"UI 随场景销毁,将在新场景中重建。"); } EnsureUi(); if (!_uiInitialized) { return; } if (!GameRefs.IsInGame) { if (_chat.IsOpen) { _chat.SetOpen(open: false); } return; } _chat.Tick(); TryApplyGameStyle(); if (_config.DebugLogGate && Time.frameCount % 60 == 0) { Log.LogInfo((object)("[诊断] 热键判定:" + GameRefs.DescribeHotkeyGate())); Log.LogInfo((object)("[诊断] 窗口:" + _chat.DescribeVisibility())); Log.LogInfo((object)("[诊断] 焦点:" + _chat.DescribeFocus())); } string reason; if (_chat.IsOpen && _hotkey.EscapePressedThisFrame) { if (_chat.InputFocused) { _chat.BlurInput(); } else { _chat.SetOpen(open: false); } } else if (_hotkey.ShouldToggle(_chat.IsOpen, _chat.InputFocused, out reason)) { bool flag = !_chat.IsOpen; _chat.SetOpen(flag); if (flag) { OnWindowOpened(); Log.LogInfo((object)("[热键] 已打开窗口。" + _chat.DescribeVisibility())); } else { Log.LogInfo((object)"[热键] 已关闭窗口。"); } } else if (_hotkey.KeyPressedThisFrame) { Log.LogInfo((object)$"[热键] {_hotkey.Key} 已按下但被拒绝:{reason}"); Log.LogInfo((object)("[热键] 判定依据:" + GameRefs.DescribeHotkeyGate())); } } private void LateUpdate() { if (_uiInitialized && _chat.WantsInputSuppressed) { GameRefs.SetTextInputActive(active: true); } } private void OnDestroy() { try { _chat?.Destroy(); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("清理 UI 失败:" + ex.Message)); } } try { _tools?.CancelAll("插件卸载"); } catch { } try { _client?.Stop(); } catch (Exception ex2) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)("停止客户端失败:" + ex2.Message)); } } try { _launcher?.Shutdown(); } catch (Exception ex3) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogWarning((object)("回收 sidecar 失败:" + ex3.Message)); } } Instance = null; } private void PrepareSidecar() { if (_sidecarStartAttempted) { return; } _sidecarStartAttempted = true; try { Log.LogInfo((object)"正在准备 sidecar…"); if (!_launcher.TryPrepare(out var options, out var error)) { Post(delegate { ShowHint(Strings.Get("hint.disconnected") + "\n" + error); }); Log.LogError((object)("sidecar 准备失败:" + error)); return; } SidecarClient sidecarClient = new SidecarClient(options); sidecarClient.StateChanged += OnClientStateChanged; sidecarClient.Received += OnClientMessage; sidecarClient.Log += delegate(string msg) { Log.LogInfo((object)("[client] " + msg)); }; sidecarClient.ConfigChanged += OnConfigChanged; _client = sidecarClient; ModelSettingsTab.Bind(sidecarClient); sidecarClient.Start(); } catch (Exception ex) { Exception ex2 = ex; Exception ex3 = ex2; Log.LogError((object)$"准备 sidecar 时异常:{ex3}"); Post(delegate { ShowHint("准备 sidecar 失败:" + ex3.Message); }); } } private void OnClientStateChanged(ConnectionState state, string detail) { Log.LogInfo((object)$"[连接] {state} {detail}"); Post(delegate { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) switch (state) { case ConnectionState.Connecting: _chat.SetStatus(Strings.Get("status.connecting")); break; case ConnectionState.Handshaking: _chat.SetStatus(Strings.Get("status.handshaking")); break; case ConnectionState.Ready: _chat.SetStatus(Strings.Get("status.ready"), OkColor); _saveSynced = false; break; case ConnectionState.Backoff: _tools.CancelAll("连接退避"); _regenerateDeleteId.Clear(); _chat.SetStatus(Strings.Get("status.backoff") + " " + detail, WarnColor); break; default: _tools.CancelAll("连接断开"); _regenerateDeleteId.Clear(); _chat.SetStatus(Strings.Get("status.disconnected")); break; } }); } private void OnClientMessage(string type, JsonValue payload, string replyTo) { Post(delegate { HandleMessage(type, payload, replyTo); }); } private void HandleMessage(string type, JsonValue payload, string replyTo) { //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) if (type == null) { return; } switch (type.Length) { case 5: switch (type[0]) { case 'r': if (type == "ready") { string text8 = payload["agent"]["model"].AsString("?"); string value3 = payload["sessionId"].AsString("?"); _chat.AppendSystem("已连接 sidecar(会话 " + Short(value3) + ",模型 " + text8 + ")"); } break; case 'e': if (type == "error") { if (!string.IsNullOrEmpty(replyTo)) { _promptById.Remove(replyTo); } string text6 = payload["code"].AsString("unknown"); string text7 = payload["message"].AsString(""); _chat.EndThinking(finalize: true); _chat.FinishTurn(); _chat.AppendSystem("⚠ 错误 [" + text6 + "] " + text7); if (_streaming) { _chat.EndStream(); _streaming = false; } } break; } break; case 6: switch (type[2]) { case 'a': { if (!(type == "status")) { break; } string text10 = payload["state"].AsString(""); switch (text10) { case "thinking": case "tools": _chat.SetStatus((text10 == "tools") ? Strings.Get("status.tools") : Strings.Get("status.thinking"), AccentColor); break; case "idle": _chat.EndThinking(finalize: true); if (_streaming) { _chat.EndStream(); _streaming = false; } _chat.FinishTurn(); _chat.SetStatus(Strings.Get("status.ready"), OkColor); break; case "retrying": _chat.EndThinking(); _chat.SetStatus("重试中…", WarnColor); break; } break; } case 'r': { if (!(type == "stream")) { break; } string text9 = payload["channel"].AsString("text"); if (text9 == "reasoning") { _chat.AppendThinkingDelta(payload["delta"].AsString("")); _chat.SetStatus(Strings.Get("status.thinking"), AccentColor); } else if (!(text9 != "text")) { if (!_streaming) { _chat.EndThinking(); _streaming = true; _chat.BeginStream(Strings.Get("agent")); } _chat.AppendStreamDelta(payload["delta"].AsString("")); } break; } } break; case 10: if (type == "save.bound") { OnSaveBound(SaveBoundInfo.Parse(payload)); } break; case 13: { if (!(type == "tool_activity")) { break; } ToolActivityInfo toolActivityInfo = ToolActivityInfo.Parse(payload); if (toolActivityInfo != null && !string.IsNullOrEmpty(toolActivityInfo.CallId)) { string name = ToolLabel(toolActivityInfo.Name); if (toolActivityInfo.Phase == "start") { _chat.BeginToolCard(toolActivityInfo.CallId, name, toolActivityInfo.Args); } else { _chat.FinishToolCard(toolActivityInfo.CallId, name, toolActivityInfo.Ok, toolActivityInfo.Summary, toolActivityInfo.Detail); } } break; } case 14: if (type == "blueprint_card") { BlueprintCardInfo blueprintCardInfo = BlueprintCardInfo.Parse(payload); if (blueprintCardInfo != null && (!string.IsNullOrEmpty(blueprintCardInfo.FileName) || !string.IsNullOrEmpty(blueprintCardInfo.Path))) { _chat.AppendBlueprintCard(blueprintCardInfo); } } break; case 15: { if (!(type == "history.deleted")) { break; } HistoryDeletedInfo historyDeletedInfo = HistoryDeletedInfo.Parse(payload); if (!string.IsNullOrEmpty(replyTo) && _regenerateDeleteId.TryGetValue(replyTo, out var value2)) { _regenerateDeleteId.Remove(replyTo); if (historyDeletedInfo == null || !historyDeletedInfo.Ok) { string text3 = ((historyDeletedInfo == null || string.IsNullOrEmpty(historyDeletedInfo.Error)) ? "未知错误" : historyDeletedInfo.Error); _chat.AppendSystem("重新推理失败(无法删除旧回答:" + text3 + ")。"); _chat.SetStatus(Strings.Get("status.ready"), OkColor); break; } _streaming = false; string text4 = ((_client != null) ? _client.SendPrompt(value2) : null); if (text4 == null) { _chat.AppendSystem("重新推理失败(连接未就绪)。"); _chat.SetStatus(Strings.Get("status.ready"), OkColor); } else { _promptById[text4] = value2; _chat.SetStatus(Strings.Get("status.thinking"), AccentColor); Log.LogInfo((object)("[刷新] 已删除旧回合,重新发送提问:" + text4)); } } else if (historyDeletedInfo != null && !historyDeletedInfo.Ok) { string text5 = (string.IsNullOrEmpty(historyDeletedInfo.Error) ? "未知错误" : historyDeletedInfo.Error); _chat.AppendSystem("删除未写入会话(" + text5 + ");重进存档可能仍会出现这条对话。"); } break; } case 7: { if (!(type == "message") || !payload["final"].AsBool()) { break; } if (!string.IsNullOrEmpty(replyTo)) { if (replyTo == _lastFinalReplyTo) { break; } _lastFinalReplyTo = replyTo; } string text = string.Empty; foreach (JsonValue item in payload["content"].Items) { if (!(item["type"].AsString() != "text")) { string text2 = item["text"].AsString(""); if (!string.IsNullOrEmpty(text2)) { text = (string.IsNullOrEmpty(text) ? text2 : (text + "\n" + text2)); } } } _chat.EndThinking(finalize: true); if (_streaming) { _chat.EndStream(); _streaming = false; } else { foreach (JsonValue item2 in payload["content"].Items) { if (item2["type"].AsString() == "text") { _chat.AppendLine(Strings.Get("agent"), item2["text"].AsString("")); } } } string value = null; if (!string.IsNullOrEmpty(replyTo)) { _promptById.TryGetValue(replyTo, out value); } if (!string.IsNullOrEmpty(value)) { _client?.SendReplyTime(value, text, ChatWindow.CurrentGameClock()); _promptById.Remove(replyTo); } break; } case 9: if (type == "tool_call") { OnToolCall(payload, replyTo); } break; case 8: case 11: case 12: break; } } private void OnToolCall(JsonValue payload, string replyTo) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) ToolCallInfo toolCallInfo = ToolCallInfo.Parse(payload, replyTo); if (toolCallInfo == null) { Log.LogWarning((object)"[tool] 收到无法解析的 tool_call"); _client?.SendToolResult(replyTo ?? string.Empty, ok: false, JsonValue.Null, "invalid_args", "tool_call 缺少 name/callId", null); return; } if (toolCallInfo.Internal) { _internalCalls.Add(toolCallInfo.CallId); } else { _chat?.SetStatus("正在读取" + ToolLabel(toolCallInfo.Name) + "…", AccentColor); if (_chat != null && _chat.Created) { _chat.BeginToolCard(toolCallInfo.CallId, ToolLabel(toolCallInfo.Name), ToolArgsText(toolCallInfo.Args)); } } if (_tools == null) { _client?.SendToolResult(toolCallInfo.CallId, ok: false, JsonValue.Null, "tool_unavailable", "工具执行器尚未初始化", null); if (!toolCallInfo.Internal && _chat != null && _chat.Created) { _chat.FinishToolCard(toolCallInfo.CallId, ToolLabel(toolCallInfo.Name), ok: false, "工具执行器尚未初始化"); } } else { GameToolOutcome gameToolOutcome = _tools.Begin(toolCallInfo.CallId, toolCallInfo.Name, toolCallInfo.Args, toolCallInfo.TimeoutMs); if (gameToolOutcome != null) { OnToolDone(gameToolOutcome); } } } private void OnToolDone(GameToolOutcome outcome) { //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (outcome == null) { return; } SendToolOutcome(outcome); if (_internalCalls.Remove(outcome.CallId)) { return; } string name = ToolLabel(outcome.Name); if (outcome.Ok) { string summary = (string.IsNullOrEmpty(outcome.Summary) ? "完成" : outcome.Summary); if (_chat != null && _chat.Created) { _chat.FinishToolCard(outcome.CallId, name, ok: true, summary, outcome.Summary); AttachToolImage(outcome); } _chat?.SetStatus(Strings.Get("status.ready"), OkColor); } else { string text = outcome.ErrorMessage ?? outcome.ErrorCode ?? "未知错误"; if (_chat != null && _chat.Created) { _chat.FinishToolCard(outcome.CallId, name, ok: false, text, text); } _chat?.SetStatus(Strings.Get("status.ready"), WarnColor); } } private static string ToolArgsText(JsonValue args) { if (args == null || args.IsNull) { return null; } string text = args.ToString(); if (string.IsNullOrEmpty(text) || text == "{}") { return null; } if (text.Length > 600) { return text.Substring(0, 600) + "…"; } return text; } private void SendToolOutcome(GameToolOutcome outcome) { if (outcome != null && _client != null && !_client.SendToolResult(outcome.CallId, outcome.Ok, outcome.Ok ? outcome.Data : JsonValue.Null, outcome.ErrorCode, outcome.ErrorMessage, outcome.Meta, outcome.Ok ? outcome.Image : null)) { Log.LogWarning((object)("[tool] tool_result 未能发出(连接未就绪)callId=" + outcome.CallId)); } } private void AttachToolImage(GameToolOutcome outcome) { JsonValue image = outcome.Image; if (image == null || !image.IsObject) { return; } string text = image["data"].AsString(); if (string.IsNullOrEmpty(text)) { return; } if (text.Length > 4194304) { Log.LogWarning((object)$"[chat] 截图过大,跳过显示(base64 {text.Length} 字符)"); return; } try { _chat.AttachToolImage(outcome.CallId, Convert.FromBase64String(text)); } catch (FormatException ex) { Log.LogWarning((object)("[chat] 截图 base64 解码失败:" + ex.Message)); } } private static string ToolLabel(string name) { return ToolNames.Label(name); } private void EnsureUi() { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) if (_uiInitialized || !GameRefs.IsInGame) { return; } UIRoot uiRoot = GameRefs.UiRoot; if ((Object)(object)uiRoot == (Object)null) { return; } if (!_styleCaptured) { _styleCaptured = UiStyle.TryCapture(uiRoot, Log); if (!_styleCaptured) { _styleWaitFrames++; if (_styleWaitFrames < 360) { return; } Log.LogWarning((object)"等待游戏样式超时,将使用内置兜底配色。"); } } Font val; try { val = FontProvider.Resolve(); } catch (Exception ex) { if (!_uiCreateFailureLogged) { _uiCreateFailureLogged = true; Log.LogError((object)("获取字体失败:" + ex.Message)); } return; } if ((Object)(object)val == (Object)null) { if (!_uiCreateFailureLogged) { _uiCreateFailureLogged = true; Log.LogError((object)"找不到可用字体,聊天窗口无法创建。"); } return; } Log.LogInfo((object)$"[UI] 界面形态:独立窗口(热键 {_hotkey.Key})"); try { _chat.Create(uiRoot, val, _config); } catch (Exception arg) { if (!_uiCreateFailureLogged) { _uiCreateFailureLogged = true; Log.LogError((object)$"创建聊天窗口失败:{arg}"); } return; } if (_styleCaptured) { _chat.ApplyStyle(UiStyle.Current); } _uiInitialized = true; ApplyConfigState(); _uiCreateFailureLogged = false; Log.LogInfo((object)("聊天窗口已创建(自建 Canvas,缩放来源 " + ChatWindow.ScalerSource + ",字体来源 " + FontProvider.Source + ")")); string text = _hotkey.RunConflictScan(); if (!string.IsNullOrEmpty(text)) { Log.LogInfo((object)("[热键] " + text)); } if (_pendingHint != null) { _chat.AppendSystem(_pendingHint); _pendingHint = null; } TryApplyGameStyle(); } private void OnKeySubmitted(string apiKey) { if (!string.IsNullOrEmpty(apiKey)) { Log.LogInfo((object)$"[配置] 收到 API Key(长度 {apiKey.Length}),上报给 sidecar…"); if (_client == null) { _chat.AppendSystem("连接未就绪,请稍后重试。"); } else if (_client.SendConfigSet(null, null, apiKey) == null) { _chat.AppendSystem("连接未就绪,请稍后重试。"); } else { _chat.SetStatus("校验中…"); } } } private void OnTurnDeleted(string text, long timestampMs) { if (!string.IsNullOrEmpty(text) && _client != null) { string saveKey = GameRefs.CurrentSaveKey(); string text2 = _client.SendHistoryDelete(saveKey, text, timestampMs); if (text2 == null) { _chat.AppendSystem("删除未同步到会话(连接未就绪);重进存档可能仍会出现这条对话。"); } else { Log.LogInfo((object)("[索引] 已请求 sidecar 删除回合:" + text2)); } } } private void OnRegenerateRequested(string text, long timestampMs) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(text)) { return; } if (_client == null || _client.State != ConnectionState.Ready) { _chat.AppendSystem("重新推理失败(连接未就绪)。"); return; } string saveKey = GameRefs.CurrentSaveKey(); string text2 = _client.SendHistoryDelete(saveKey, text, timestampMs); if (text2 == null) { _chat.AppendSystem("重新推理失败(连接状态已变化)。"); return; } _regenerateDeleteId[text2] = text; _chat.SetStatus(Strings.Get("status.regenerating"), AccentColor); Log.LogInfo((object)("[刷新] 请求删除旧回合后重新推理:" + text2)); } private void OnThinkingLevelChanged(string level) { if (PluginConfig.IsValidThinkingLevel(level)) { _config?.SetThinkingLevel(level); if (_client == null || _client.State != ConnectionState.Ready) { _thinkingLevelDirty = true; Log.LogInfo((object)("[配置] 思考档位 → " + level + "(连接未就绪,稍后补发)")); return; } string text = _client.SendConfigSet(null, null, null, null, level); _thinkingLevelDirty = text == null; Log.LogInfo((object)("[配置] 思考档位 → " + level + "(config.set " + ((text != null) ? "已发送" : "发送失败") + ")")); } } private void OnModelSelectionChanged(string provider, string model) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model)) { if (_client == null || _client.State != ConnectionState.Ready) { _chat?.SetStatus("sidecar 未连接,模型选择未生效", WarnColor); Log.LogInfo((object)("[配置] 模型 → " + provider + "/" + model + "(连接未就绪,未发送)")); } else if (_client.SendConfigSet(null, null, null, null, null, null, null, provider, model) == null) { _chat?.SetStatus("模型选择发送失败", WarnColor); Log.LogWarning((object)("[配置] 模型 → " + provider + "/" + model + "(config.set 发送失败)")); } else { _chat?.SetStatus(Strings.Get("model.switched", provider + "/" + model), OkColor); Log.LogInfo((object)("[配置] 模型 → " + provider + "/" + model + "(config.set 已发送)")); } } } private void OnConfigChanged(ConfigState config) { if (config != null) { Log.LogInfo((object)$"[配置] 状态:{config}"); _lastConfig = config; Post(ApplyConfigState); } } private void ApplyConfigState() { ConfigState lastConfig = _lastConfig; if (lastConfig != null && _chat != null && _uiInitialized) { if (lastConfig.State == "ready" && _thinkingLevelDirty && _client != null) { string text = _client.SendConfigSet(null, null, null, null, _config.ThinkingLevel); _thinkingLevelDirty = text == null; } if (_thinkingLevelDirty) { _chat.ApplyThinkingLevel(_config.ThinkingLevel); } else if (!string.IsNullOrEmpty(lastConfig.ThinkingLevel)) { _chat.ApplyThinkingLevel(lastConfig.ThinkingLevel); } _chat.ApplyModels(lastConfig); switch (lastConfig.State) { case "missing_key": _chat.EnterKeyEntry(null); break; case "invalid_key": _chat.EnterKeyEntry(Strings.Get("key.invalid")); break; case "unreachable": _chat.AppendSystem(Strings.Get("key.unreachable")); _chat.EnterKeyEntry(null); break; case "ready": _chat.ExitKeyEntry(); _chat.SetStatus(Strings.Get("status.ready")); break; } } } private void SyncSaveBinding() { if (_client == null) { return; } string text = GameRefs.CurrentSaveKey(); if (text != _saveKey) { _tools?.CancelAll("存档切换", OnToolDone); _tools?.ClearCache(); _saveKey = text; _saveSynced = false; _historyReplayedFor = null; _internalCalls.Clear(); if (_chat != null && _chat.Created) { _chat.ClearTranscript(); } Log.LogInfo((object)("[存档] 当前存档变化:" + (text ?? "(无,主菜单)"))); } if (_saveSynced || _client.State != ConnectionState.Ready) { return; } string text2 = ((text != null) ? GameRefs.CurrentSaveName() : null); JsonValue jsonValue = null; if (text != null) { GameRefs.BlueprintTierInfo blueprintTierInfo = GameRefs.CurrentBlueprintTiers(); if (blueprintTierInfo.Available) { jsonValue = JsonValue.NewObject(); jsonValue.Set("assembler", blueprintTierInfo.Assembler); jsonValue.Set("belt", blueprintTierInfo.Belt); jsonValue.Set("inserter", blueprintTierInfo.Inserter); jsonValue.Set("piler", blueprintTierInfo.Piler); jsonValue.Set("stacking", blueprintTierInfo.Stacking); } } if (_client.SendSaveBind(text, text2, jsonValue) != null) { _saveSynced = true; Log.LogInfo((object)("[存档] 已上报绑定:" + (text ?? "(解绑)") + " / " + (text2 ?? "-"))); } } private void OnSaveBound(SaveBoundInfo info) { if (info == null) { return; } Post(delegate { //IL_034f: Unknown result type (might be due to invalid IL or missing references) if (_chat != null) { if (string.IsNullOrEmpty(info.SaveKey)) { _historyReplayedFor = null; _chat.AppendSystem(Strings.Get("save.unbound")); } else { string text = (string.IsNullOrEmpty(info.SaveName) ? info.SaveKey : info.SaveName); bool flag = info.History != null && info.History.Count > 0 && info.SaveKey != _historyReplayedFor && !_streaming; if (flag) { _chat.ClearTranscript(); } if (!info.Existed) { _chat.AppendSystem(Strings.Get("save.new", text)); } else if (info.MessageCount > 0) { _chat.AppendSystem(Strings.Get("save.bound", text, info.MessageCount)); } else { _chat.AppendSystem(Strings.Get("save.bound.nocount", text)); } if (flag) { int num = 0; int num2 = 0; foreach (HistoryMessageInfo item in info.History) { if (item != null && !string.IsNullOrEmpty(item.Text)) { try { if (item.Role == "user") { _chat.AppendUser(item.Text, item.Timestamp, item.GameTime); } else { _chat.AppendHistoryReply(item); if (item.Cards != null) { foreach (BlueprintCardInfo card in item.Cards) { if (card != null && string.IsNullOrEmpty(card.CreatedAt) && item.Timestamp > 0) { card.CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(item.Timestamp).LocalDateTime.ToString("yyyy-MM-dd"); } _chat.AppendBlueprintCard(card); } } } num++; } catch (Exception ex) { num2++; Log.LogWarning((object)("[存档] 回放历史消息失败(" + item.Role + "):" + ex.Message)); } } } if (num2 == 0) { _historyReplayedFor = info.SaveKey; } Log.LogInfo((object)$"[存档] 回放历史:{num} 条,失败 {num2} 条(存档 {info.SaveKey})"); } _chat.SetStatus(Strings.Get("status.ready"), OkColor); } } }); } private void TryApplyGameStyle() { if (!_styleApplied && _uiInitialized) { UIRoot uiRoot = GameRefs.UiRoot; if (!((Object)(object)uiRoot == (Object)null) && UiStyle.TryCapture(uiRoot, Log)) { _styleCaptured = true; _chat.ApplyStyle(UiStyle.Current); _styleApplied = true; Log.LogInfo((object)"[样式] 已套用游戏原生面板样式。"); } } } private void OnWindowOpened() { if (!_welcomeShown && _chat.TranscriptEmpty) { _welcomeShown = true; _chat.AppendSystem(Strings.Get("welcome")); } if (_client == null) { _chat.AppendSystem(Strings.Get("hint.disconnected")); } else if (_client.State != ConnectionState.Ready) { _chat.SetStatus(Strings.Get("status.connecting")); } } private void ShowHint(string hint) { if (_chat.Created) { _chat.AppendSystem(hint); } else { _pendingHint = hint; } } private void OnBlueprintCardAction(BlueprintCardInfo card, BlueprintCardAction action) { if (card != null) { bool flag; string error; try { flag = ((action != BlueprintCardAction.Inspect) ? BlueprintActions.TryPaste(card, out error) : BlueprintActions.TryInspect(card, out error)); } catch (Exception ex) { Log.LogWarning((object)$"[蓝图卡] {action} 异常:{ex.Message}"); flag = false; error = Strings.Get("blueprint.card.not_in_game"); } if (!flag) { Log.LogInfo((object)$"[蓝图卡] {action} 失败:{error}"); _chat.AppendSystem(error ?? Strings.Get("blueprint.card.open_failed")); } else { _chat.SetOpen(open: false); } } } private void OnUserSubmitted(string text) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(text)) { return; } _chat.AppendUser(text, 0L); if (_client == null || _client.State != ConnectionState.Ready) { _chat.AppendSystem("尚未连接到 sidecar,消息未发送。"); return; } _streaming = false; string text2 = _client.SendPrompt(text); if (text2 == null) { _chat.AppendSystem("发送失败(连接状态已变化)。"); return; } _promptById[text2] = text; _chat.SetStatus(Strings.Get("status.thinking"), AccentColor); } private void Post(Action action) { _dispatcher.Post(action); } private string ResolvePluginDir() { try { PluginInfo info = ((BaseUnityPlugin)this).Info; string text = ((info != null) ? info.Location : null); if (!string.IsNullOrEmpty(text)) { string directoryName = Path.GetDirectoryName(text); if (!string.IsNullOrEmpty(directoryName)) { return directoryName; } } } catch { } return Paths.PluginPath; } private static string Short(string value) { if (string.IsNullOrEmpty(value)) { return "?"; } if (value.Length > 8) { return value.Substring(0, 8) + "…"; } return value; } } } namespace IcarusII.UI { public sealed class ChatIndexRowHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerClickHandler { public GameObject DeleteButton; public Graphic HoverBackground; public Color HoverColor = new Color(0.35f, 0.75f, 1f, 0.1f); public Color SelectedColor = new Color(0.35f, 0.75f, 1f, 0.16f); private bool _hovered; private bool _selected; public event Action Clicked; public void SetSelected(bool selected) { _selected = selected; Apply(); } public void OnPointerEnter(PointerEventData eventData) { _hovered = true; Apply(); } public void OnPointerExit(PointerEventData eventData) { _hovered = false; Apply(); } public void OnPointerClick(PointerEventData eventData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)eventData.button == 0) { this.Clicked?.Invoke(); } } private void OnDisable() { _hovered = false; Apply(); } private void Apply() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DeleteButton != (Object)null) { DeleteButton.SetActive(_hovered); } if ((Object)(object)HoverBackground != (Object)null) { HoverBackground.color = (_selected ? SelectedColor : (_hovered ? HoverColor : Color.clear)); } } } internal sealed class ClickToFocus : MonoBehaviour, IPointerClickHandler, IEventSystemHandler { public ChatWindow Target; public void OnPointerClick(PointerEventData eventData) { Target?.FocusInput(); } } internal enum BlueprintCardAction { Inspect, Paste } internal sealed class ChatWindow { private enum LineKind { Assistant, User, System, Blueprint } private struct Line { public LineKind Kind; public string Text; public int TurnId; public GameObject Go; public Block Block; public List<BlueprintCardInfo> Cards; public List<ThinkingSegment> Thinking; public List<HistoryStepInfo> Steps; public string Time; } private struct ThinkingSegment { public string Text; public string Summary; } private struct Item { public GameObject Go; public Text Label; public LineKind Kind; public int TurnId; public bool FromPrefab; public ReplyView Reply; public GameObject Footer; public Text FooterTime; public Button FooterCopy; } private sealed class TurnEntry { public int Id; public string Text; public long Timestamp; public GameObject UserGo; public GameObject Row; public Text Link; public ChatIndexRowHover Hover; } private sealed class ModelChoice { public string Provider; public string Model; public string Label; } private sealed class Block { public GameObject Go; public Image Accent; public Text Chevron; public Text Title; public LayoutElement TitleLayout; public Text Summary; public Text Body; public bool Expanded; public string Args; public string ToolName; public string RawBody; public RectTransform ImageRt; public ToolImageSprite ImageOwner; public ReplyView Reply; } private sealed class ReplyView { public GameObject Go; public Text Body; public GameObject Footer; public Text Time; public Button Copy; public Text CopyLabel; public RectTransform ThinkingRoot; public Block Thinking; public readonly List<Block> ThinkingBlocks = new List<Block>(); public readonly List<Block> Blocks = new List<Block>(); public RectTransform Loading; public GameObject LoadingHeader; public RectTransform LoadingContent; public Image LoadingSpinner; public LoadingSpinner LoadingSpin; public Text LoadingChevron; public Text LoadingTitle; public bool LoadingExpanded = true; public bool LoadingDone; public RectTransform Tools; public RectTransform ToolTemplate; public RectTransform BlueprintCards; public RectTransform CardTemplate; public readonly List<CardView> CardViews = new List<CardView>(); public string CopyText = string.Empty; public int TurnId; public Button Refresh; } private sealed class CardView { public GameObject Go; public BlueprintCardInfo Card; public GameObject ThumbIconRoot; public Image ThumbIcon; public GameObject ThumbFallback; public Text ThumbLabel; public Text Name; public Text Description; public Text Meta; public Button CardButton; public Button ViewButton; public Button UseButton; public Text ViewLabel; public Text UseLabel; } private const int MaxTranscriptChars = 120000; private const float MaxBubbleWidth = 260f; private const float BubblePaddingX = 12f; private const float DefaultPanelWidth = 780f; private const float DefaultPanelHeight = 520f; private static readonly Color DefaultPanelBg = new Color(0.055f, 0.082f, 0.125f, 0.97f); private static readonly Color DefaultHeaderBg = new Color(0.098f, 0.157f, 0.235f, 1f); private static readonly Color DefaultInputBg = new Color(0.098f, 0.129f, 0.18f, 1f); private static readonly Color DefaultTextMain = new Color(0.878f, 0.918f, 0.961f, 1f); private static readonly Color DefaultTextDim = new Color(0.596f, 0.678f, 0.757f, 1f); private static readonly Color DefaultAccent = new Color(0.353f, 0.749f, 1f, 1f); private Color _textMain = DefaultTextMain; private Color _textDim = DefaultTextDim; private Color _accent = DefaultAccent; private GameObject _root; private Canvas _canvas; private Canvas _hostCanvas; private float _canvasScale = 1f; private bool _fromPrefab; private RectTransform _panel; private RectTransform _content; private Image _panelImage; private Image _frameImage; private Image _glassImage; private Image _headerImage; private Image _inputImage; private Text _statusText; private Text _titleText; private bool _titleFromPrefab; private Text _transcript; private ScrollRect _scroll; private InputField _input; private ScrollRect _inputScrollRect; private RectTransform _inputViewport; private RectTransform _inputContent; private bool _caretPrimed; private int _iconMapTick; private bool _iconMapReady; private static readonly FieldInfo InputCaretRendererField = typeof(InputField).GetField("m_CachedInputRenderer", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo InputCaretVisibleField = typeof(InputField).GetField("m_CaretVisible", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo InputAllowInputField = typeof(InputField).GetField("m_AllowInput", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo InputSetCaretVisibleMethod = typeof(InputField).GetMethod("SetCaretVisible", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo InputUpdateCaretMaterialMethod = typeof(InputField).GetMethod("UpdateCaretMaterial", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo InputMarkGeometryDirtyMethod = typeof(InputField).GetMethod("MarkGeometryAsDirty", BindingFlags.Instance | BindingFlags.NonPublic); private readonly List<Line> _lines = new List<Line>(); private readonly List<Item> _items = new List<Item>(); private readonly Dictionary<string, Block> _toolBlocks = new Dictionary<string, Block>(StringComparer.Ordinal); private Block _thinking; private readonly StringBuilder _thinkingText = new StringBuilder(); private UIComboBox _thinkingCombo; private string _thinkingLevel = "high"; private bool _suppressThinkingLevelEvent; private UIComboBox _modelCombo; private readonly List<ModelChoice> _modelChoices = new List<ModelChoice>(); private string _modelProvider = string.Empty; private string _modelId = string.Empty; private string _modelSignature = string.Empty; private bool _suppressModelEvent; private ConfigState _pendingModelState; private static readonly Color WarnColor = new Color(1f, 0.47f, 0.32f, 1f); private readonly StringBuilder _stream = new StringBuilder(); private int _streamItem = -1; private int _itemSeq; private RectTransform _userTemplate; private RectTransform _assistantTemplate; private RectTransform _replyTemplate; private RectTransform _chatIndex; private RectTransform _chatIndexContent; private RectTransform _chatIndexTemplate; private ScrollRect _chatIndexScroll; private Text _chatIndexTitle; private Text _chatIndexEmpty; private readonly List<TurnEntry> _turns = new List<TurnEntry>(); private int _nextTurnId; private int _currentTurnId; private int _focusedTurnId; private bool _awaitingResponse; private Font _bodyFont; private string _authoredPlaceholder; private bool _dirty; private bool _suppressAutoScrollOnce; private int _scrollBottomFrames; private int _fontSize; private int _maxLines; private int _tipLayerTick; private bool _savedInputing; private bool _autoFocusInput; private bool _wantInputFocus; private bool _keyEntryMode; private bool _submitPending; private bool _textMaterialRebound; private string _lastInputText; private static string _scalerSource = "default"; private static TextIconMapping _iconTagSource; private static HashSet<string> _iconTags; private Button _iconToolButton; private Button _colorToolButton; private bool ViewVisible { get { if ((Object)(object)_root != (Object)null) { return _root.activeSelf; } return false; } } public string SelectedProvider => _modelProvider; public string SelectedModel => _modelId; public bool WantsInputSuppressed => IsOpen; public bool InputFocused { get { if ((Object)(object)_input != (Object)null) { return _input.isFocused; } return false; } } public bool KeyEntryMode => _keyEntryMode; public bool IsOpen { get; private set; } public bool Alive => (Object)(object)_root != (Object)null; public bool Created => (Object)(object)_root != (Object)null; public static string ScalerSource => _scalerSource; public string ThinkingLevel => _thinkingLevel; public bool TranscriptEmpty { get { if (_lines.Count == 0) { return _streamItem < 0; } return false; } } public event Action<string, string> ModelSelectionChanged; public event Action<string> Submitted; public event Action<BlueprintCardInfo, BlueprintCardAction> BlueprintCardActionRequested; public event Action<string> KeySubmitted; public event Action<string, long> TurnDeleted; public event Action<string, long> RegenerateRequested; public event Action<string> ThinkingLevelChanged; public void FocusInput() { if (!((Object)(object)_input == (Object)null)) { _wantInputFocus = true; _caretPrimed = false; ApplyFocus(); } } public void BlurInput() { if (!((Object)(object)_input == (Object)null)) { _wantInputFocus = false; _caretPrimed = false; _input.DeactivateInputField(true); EventSystem current = EventSystem.current; if ((Object)(object)current != (Object)null && (Object)(object)current.currentSelectedGameObject == (Object)(object)((Component)_input).gameObject) { current.SetSelectedGameObject((GameObject)null); } } } private void PrimeInputCaret() { if ((Object)(object)_input == (Object)null || !_input.isFocused) { return; } try { if (InputAllowInputField != null) { object value = InputAllowInputField.GetValue(_input); if (value is bool && !(bool)value) { return; } } if (_input.caretWidth < 2) { _input.caretWidth = 2; } _input.caretBlinkRate = 0f; object? obj = InputCaretRendererField?.GetValue(_input); CanvasRenderer val = (CanvasRenderer)((obj is CanvasRenderer) ? obj : null); if ((Object)(object)val != (Object)null && (Object)(object)val.GetMaterial() == (Object)null) { InputUpdateCaretMaterialMethod?.Invoke(_input, null); } bool flag = default(bool); int num; if (InputCaretVisibleField != null) { object value = InputCaretVisibleField.GetValue(_input); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) == 0) { InputSetCaretVisibleMethod?.Invoke(_input, null); InputMarkGeometryDirtyMethod?.Invoke(_input, null); _input.ForceLabelUpdate(); } bool flag2 = default(bool); int num2; if (InputCaretVisibleField != null) { object value = InputCaretVisibleField.GetValue(_input); if (value is bool) { flag2 = (bool)value; num2 = 1; } else { num2 = 0; } } else { num2 = 0; } if (((uint)num2 & (flag2 ? 1u : 0u)) != 0) { _caretPrimed = true; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("补输入光标失败:" + ex.Message)); } } private void ApplyFocus() { if ((Object)(object)_input == (Object)null) { return; } try { EventSystem current = EventSystem.current; if ((Object)(object)current != (Object)null && (Object)(object)current.currentSelectedGameObject != (Object)(object)((Component)_input).gameObject) { current.SetSelectedGameObject(((Component)_input).gameObject); } _input.ActivateInputField(); ((Selectable)_input).Select(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("聚焦输入框失败:" + ex.Message)); } } public string DescribeFocus() { EventSystem current = EventSystem.current; string text = (((Object)(object)current != (Object)null && (Object)(object)current.currentSelectedGameObject != (Object)null) ? ((Object)current.currentSelectedGameObject).name : "null"); return $"want={_wantInputFocus} isFocused={(Object)(object)_input != (Object)null && _input.isFocused} " + $"interactable={(Object)(object)_input != (Object)null && ((Selectable)_input).interactable} " + "eventSystem=" + (((Object)(object)current != (Object)null) ? ((Object)current).name : "NULL") + " selected=" + text; } public void Reset() { _root = null; _canvas = null; _hostCanvas = null; _canvasScale = 1f; _panel = null; _content = null; _statusText = null; _titleText = null; _titleFromPrefab = false; _transcript = null; _scroll = null; _input = null; _fromPrefab = false; _lines.Clear(); _items.Clear(); _toolBlocks.Clear(); _thinking = null; _thinkingText.Length = 0; _thinkingCombo = null; _suppressThinkingLevelEvent = false; _stream.Length = 0; _streamItem = -1; _scrollBottomFrames = 0; _userTemplate = null; _assistantTemplate = null; _replyTemplate = null; _chatIndex = null; _chatIndexContent = null; _chatIndexTemplate = null; _chatIndexScroll = null; _chatIndexTitle = null; _chatIndexEmpty = null; _turns.Clear(); _nextTurnId = 0; _currentTurnId = 0; _focusedTurnId = 0; _bodyFont = null; _authoredPlaceholder = null; _dirty = false; IsOpen = false; _wantInputFocus = false; } public void Create(UIRoot uiRoot, Font font, PluginConfig config) { //IL_013d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root != (Object)null) { return; } int num = (UiStyle.Current.HasText ? UiStyle.Current.BaseFontSize : 14); _fontSize = Mathf.RoundToInt((float)num * Mathf.Max(0.5f, config.FontScale)); _maxLines = Mathf.Max(50, config.MaxTranscriptLines); _autoFocusInput = config.AutoFocusInput; _thinkingLevel = (PluginConfig.IsValidThinkingLevel(config.ThinkingLevel) ? config.ThinkingLevel.ToLowerInvariant() : "high"); _bodyFont = font; UiFactory.EnsureEventSystem(); RectTransform val = CreateCanvas(uiRoot); _root = ((Component)val).gameObject; NativeTipLayer.Ensure(uiRoot); GameObject val2 = WindowPrefab.Instantiate((Transform)(object)val); if ((Object)(object)val2 != (Object)null && TryWireFromPrefab(val2, config, font)) { Plugin.Log.LogInfo((object)("[UI] 窗口来自 prefab(" + WindowPrefab.Status + ")")); } else { if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); Plugin.Log.LogWarning((object)"[UI] prefab 结构不完整,回退到代码构建"); } BuildUiInCode(val, config, font); } ApplyHostScaleAndLayer(); EnsureChatIndex(); ApplySoftTextMaterials(); RebuildTranscript(); SetStatus(Strings.Get("status.disconnected"), _textDim); _root.SetActive(false); } private RectTransform CreateCanvas(UIRoot uiRoot) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) Canvas val = null; try { if ((Object)(object)uiRoot != (Object)null) { val = uiRoot.overlayCanvas; } } catch { } RectTransform val2 = UiFactory.Node("IcarusIICanvas", ((Object)(object)val != (Object)null) ? ((Component)val).transform : null); Canvas val3 = (_canvas = ((Component)val2).gameObject.AddComponent<Canvas>()); if ((Object)(object)val != (Object)null) { val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.pivot = new Vector2(0.5f, 0.5f); val2.anchoredPosition = Vector2.zero; val2.sizeDelta = Vector2.zero; ((Transform)val2).localScale = Vector3.one; val3.overrideSorting = true; val3.sortingOrder = 30000; val3.additionalShaderChannels = val.additionalShaderChannels; _hostCanvas = val; _canvasScale = Mathf.Max(0.01f, val.scaleFactor); ((Component)val2).gameObject.layer = ((Component)val).gameObject.layer; } else { Plugin.Log.LogWarning((object)"[UI] 拿不到游戏的 Overlay Canvas,退回顶层 Overlay 画布。"); Object.DontDestroyOnLoad((Object)(object)((Component)val2).gameObject); val3.renderMode = (RenderMode)0; val3.sortingOrder = 30000; CopyScalerSettings(((Component)val2).gameObject.AddComponent<CanvasScaler>(), uiRoot); _canvasScale = 1f; } ((Component)val2).gameObject.AddComponent<GraphicRaycaster>(); return val2; } private void ApplyHostScaleAndLayer() { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null) && !((Object)(object)_panel == (Object)null)) { if ((Object)(object)_hostCanvas != (Object)null) { _canvasScale = Mathf.Max(0.01f, _hostCanvas.scaleFactor); ((Transform)_panel).localScale = new Vector3(1f / _canvasScale, 1f / _canvasScale, 1f); SetLayerRecursively(_root.transform, ((Component)_hostCanvas).gameObject.layer); } else { _canvasScale = 1f; ((Transform)_panel).localScale = Vector3.one; } } } private static void SetLayerRecursively(Transform t, int layer) { if (!((Object)(object)t == (Object)null)) { ((Component)t).gameObject.layer = layer; for (int i = 0; i < t.childCount; i++) { SetLayerRecursively(t.GetChild(i), layer); } } } private void BuildUiInCode(RectTransform rootRt, PluginConfig config, Font font) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) _fromPrefab = false; _panel = UiFactory.Node("Panel", (Transform)(object)rootRt); ApplyPanelPlacement(_panel, config); _panelImage = UiFactory.AddPanel(_panel, DefaultPanelBg); RectTransform val = UiFactory.Node("Frame", (Transform)(object)_panel); UiFactory.Stretch(val); _frameImage = ((Component)val).gameObject.AddComponent<Image>(); ((Graphic)_frameImage).raycastTarget = false; RectTransform val2 = UiFactory.Node("Glass", (Transform)(object)_panel); UiFactory.Stretch(val2); _glassImage = ((Component)val2).gameObject.AddComponent<Image>(); ((Graphic)_glassImage).raycastTarget = false; ((Component)_panel).gameObject.AddComponent<ClickToFocus>().Target = this; BuildHeader(font); BuildTranscript(font); BuildInputBar(font); } private bool TryWireFromPrefab(GameObject panelGo, PluginConfig config, Font font) { //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Expected O, but got Unknown //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown RectTransform component = panelGo.GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { return false; } Image val = FindImage(component, "panel-bg"); if ((Object)(object)val == (Object)null) { val = panelGo.GetComponent<Image>(); } Image val2 = FindImage(component, "panel-bg/border", "border", "Frame"); Image val3 = FindImage(component, "panel-bg/glass", "glass", "Glass"); Image headerImage = FindImage(component, "Header"); Text statusText = FindText(component, "Header/Status", "Header/title-status", "panel-bg/status-text", "status-text", "Status"); ScrollRect val4 = FindComponent<ScrollRect>(component, new string[4] { "output/scroll-view", "Scroll", "scroll-view", "transcript" }); Transform obj = FindNode(component, "output/scroll-view/viewport/content", "Scroll/Viewport/Content", "Viewport/Content", "Content", "transcript/Viewport/Content", "transcript/content", "content"); RectTransform val5 = (RectTransform)(object)((obj is RectTransform) ? obj : null); Text transcript = (((Object)(object)val5 != (Object)null) ? ((Component)val5).GetComponent<Text>() : null); Transform val6 = FindNode(component, "input/editor/scroll-view/viewport/content/InputField/input", "editor/scroll-view/viewport/content/InputField/input", "InputBar/Input", "input", "InputBar", "input-bar", "Input"); InputField val7 = (((Object)(object)val6 != (Object)null) ? ((Component)val6).GetComponent<InputField>() : null); if ((Object)(object)val7 == (Object)null) { InputField[] componentsInChildren = ((Component)component).GetComponentsInChildren<InputField>(true); foreach (InputField val8 in componentsInChildren) { if (((Component)val8).gameObject.activeInHierarchy && !IsInsideToolbar(((Component)val8).transform, component)) { val7 = val8; break; } } } Image inputImage = (((Object)(object)val7 != (Object)null) ? ((Component)val7).GetComponent<Image>() : null); Transform obj2 = FindNode(component, "input/editor/scroll-view", "editor/scroll-view"); RectTransform val9 = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null); if ((Object)(object)val9 != (Object)null) { Transform obj3 = ((Transform)val9).Find("viewport"); RectTransform val10 = (RectTransform)(object)((obj3 is RectTransform) ? obj3 : null); RectTransform val11 = (RectTransform)(((Object)(object)val10 != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val10 != (Object)null && (Object)(object)val11 != (Object)null) { _inputScrollRect = ((Component)val9).GetComponent<ScrollRect>(); _inputViewport = val10; _inputContent = val11; } } if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val7 == (Object)null) { Plugin.Log.LogWarning((object)($"[UI] prefab 缺少必需节点:panel={(Object)(object)val != (Object)null} frame={(Object)(object)val2 != (Object)null} " + $"glass={(Object)(object)val3 != (Object)null} input={(Object)(object)val7 != (Object)null}")); return false; } if ((Object)(object)val5 == (Object)null) { Plugin.Log.LogWarning((object)"[UI] prefab 缺少正文容器 output/scroll-view/viewport/content"); return false; } if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val5).GetComponentInParent<ScrollRect>(); } _fromPrefab = true; _panel = component; _panelImage = val; _frameImage = val2; _glassImage = val3; _headerImage = headerImage; _statusText = statusText; _scroll = val4; _content = val5; _transcript = transcript; _input = val7; _inputImage = inputImage; CaptureTemplates(val5); ApplyPanelPlacement(_panel, config, keepAuthoredSize: true); Button val12 = FindComponent<Button>(component, new string[3] { "panel-bg/btn-box/close-wnd-btn", "btn-box/close-wnd-btn", "close-wnd-btn" }); if ((Object)(object)val12 != (Object)null) { ((UnityEvent)val12.onClick).AddListener(new UnityAction(OnCloseButtonClicked)); if ((Object)(object)((Component)val12).GetComponent("UIButton") == (Object)null) { Plugin.Log.LogWarning((object)"关闭按钮缺少原生 UIButton,悬停/音效不可用"); } } else { Plugin.Log.LogWarning((object)"prefab 里没有关闭按钮(panel-bg/btn-box/close-wnd-btn),只能按 R 关窗。"); } WireSettingsButton(component); Button val13 = FindComponent<Button>(component, new string[4] { "input/editor/tool-bar/send-button", "tool-bar/send-button", "send-button", "SendButton" }); if ((Object)(object)val13 != (Object)null) { ((UnityEvent)val13.onClick).AddListener(new UnityAction(SubmitPendingInput)); } else { Plugin.Log.LogInfo((object)"prefab 里没有发送按钮,改用 Enter 发送(Ctrl+Enter 换行)。"); } WireInputToolbar(component); WireThinkingLevelCombo(component); WireModelCombo(component); UIWindowDrag component2 = panelGo.GetComponent<UIWindowDrag>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.screenRect == (Object)null) { Canvas componentInParent = panelGo.GetComponentInParent<Canvas>(); component2.screenRect = (RectTransform)(((Object)(object)componentInParent != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)component)); Plugin.Log.LogInfo((object)"[UI] 已补上 UIWindowDrag.screenRect(窗口可拖拽,且不再抛 NRE)。"); } SeedInputCharColors(val7, "建窗"); RebindInputTextMaterial(val7.textComponent, "建窗"); if ((Object)(object)_transcript != (Object)null && (Object)(object)_input.textComponent != (Object)null) { _transcript.iconMapping = _input.textComponent.iconMapping; _transcript.supportRichText = true; } ((UnityEvent<string>)(object)_input.onEndEdit).AddListener((UnityAction<string>)OnInputEndEdit); _input.OnNewLine += OnInputNewLine; ((Component)_panel).gameObject.AddComponent<ClickToFocus>().Target = this; Text val14 = FindText(component, "Header/Title", "Header/title-text", "panel-bg/title-text", "title-text"); bool flag = (Object)(object)val14 != (Object)null && !string.IsNullOrEmpty(val14.text); if ((Object)(object)val14 != (Object)null && !flag) { val14.text = Strings.Get("title"); } _titleText = val14; _titleFromPrefab = flag; Transform val15 = ((Component)val7).transform.Find("Placeholder"); if ((Object)(object)val15 != (Object)null) { Text component3 = ((Component)val15).GetComponent<Text>(); if ((Object)(object)component3 != (Object)null) { _authoredPlaceholder = component3.text; } } float num = Mathf.Max(0.5f, config.FontScale); _bodyFont = font; Text[] componentsInChildren2 = panelGo.GetComponentsInChildren<Text>(true); foreach (Text val16 in componentsInChildren2) { if (!_titleFromPrefab || val16 != _titleText) { if ((Object)(object)font != (Object)null) { val16.font = font; } if (!Mathf.Approximately(num, 1f)) { val16.fontSize = Mathf.Max(8, Mathf.RoundToInt((float)val16.fontSize * num)); } } } Text val17 = (((Object)(object)_input != (Object)null) ? _input.textComponent : null); if ((Object)(object)val17 != (Object)null) { ApplyBodyFont(val17); } if ((Object)(object)_input != (Object)null) { Graphic placeholder = _input.placeholder; Text val18 = (Text)(object)((placeholder is Text) ? placeholder : null); if (val18 != null) { ApplyBodyFont(val18); } } Plugin.Log.LogInfo((object)("[UI] 正文字体 = " + (((Object)(object)font != (Object)null) ? ((Object)font).name : "null") + "(来源 " + FontProvider.Source + (string.IsNullOrEmpty(FontProvider.Detail) ? "" : (";" + FontProvider.Detail)) + "),输入框与正文共用。")); return true; } private static bool IsInsideToolbar(Transform node, RectTransform panel) { Transform val = node; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)panel) { if (((Object)val).name == "tool-bar") { return true; } val = val.parent; } return false; } private static Transform FindNode(RectTransform root, params string[] paths) { foreach (string text in paths) { if (!string.IsNullOrEmpty(text)) { Transform val = ((Transform)root).Find(text); if ((Object)(object)val != (Object)null) { return val; } } } return null; } private static Image FindImage(RectTransform root, params string[] paths) { Transform val = FindNode(root, paths); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<Image>(); } private static Text FindText(RectTransform root, params string[] paths) { Transform val = FindNode(root, paths); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<Text>(); } private static T FindComponent<T>(RectTransform root, params string[] paths) where T : Component { Transform val = FindNode(root, paths); if ((Object)(object)val != (Object)null) { return ((Component)val).GetComponent<T>(); } return ((Component)root).GetComponentInChildren<T>(true); } private static void ApplyPanelPlacement(RectTransform panel, PluginConfig config, bool keepAuthoredSize = false) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) Vector2 size = default(Vector2); ((Vector2)(ref size))..ctor(config.PanelWidth, config.PanelHeight); string a = (config.PositionMode ?? "center").Trim(); if (keepAuthoredSize && Mathf.Approximately(config.PanelWidth, 780f) && Mathf.Approximately(config.PanelHeight, 520f)) { Vector2 sizeDelta = panel.sizeDelta; if (sizeDelta.x > 1f && sizeDelta.y > 1f) { size = sizeDelta; Plugin.Log.LogInfo((object)$"[UI] 使用 prefab 里的窗口尺寸 {sizeDelta.x:0}x{sizeDelta.y:0}(配置未自定义)。"); } } if (string.Equals(a, "bottomRight", StringComparison.OrdinalIgnoreCase)) { UiFactory.AnchoredTo(panel, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-24f, 24f), size); } else { UiFactory.AnchoredTo(panel, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, size); } } private void BuildHeader(Font font) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) RectTransform val = UiFactory.Node("Header", (Transform)(object)_panel); UiFactory.TopBar(val, 34f); _headerImage = UiFactory.AddPanel(val, DefaultHeaderBg); RectTransform rt = UiFactory.Node("Title", (Transform)(object)val); UiFactory.Stretch(rt, 12f, 0f, 260f); UiFactory.AddLabel(rt, font, _fontSize + 2, _accent, (TextAnchor)3).text = Strings.Get("title"); RectTransform rt2 = UiFactory.Node("Status", (Transform)(object)val); UiFactory.Stretch(rt2, 200f, 0f, 12f); _statusText = UiFactory.AddLabel(rt2, font, _fontSize - 1, _textDim, (TextAnchor)5); _statusText.text = string.Empty; } private void BuildTranscript(Font font) { CreateTranscript(_panel, font, autoFit: false); } private void CreateTranscript(RectTransform parent, Font font, bool autoFit) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown RectTransform val = UiFactory.Node("Scroll", (Transform)(object)parent); if (autoFit) { UiFactory.Stretch(val, 20f, 64f, 20f, 110f); AutoFitTranscript(val, parent); } else { UiFactory.Stretch(val, 8f, 40f, 8f, 44f); } _scroll = ((Component)val).gameObject.AddComponent<ScrollRect>(); _scroll.horizontal = false; _scroll.vertical = true; _scroll.movementType = (MovementType)2; _scroll.scrollSensitivity = 30f; RectTransform val2 = UiFactory.Node("Viewport", (Transform)(object)val); UiFactory.Stretch(val2); ((Component)val2).gameObject.AddComponent<RectMask2D>(); Image obj = ((Component)val2).gameObject.AddComponent<Image>(); ((Graphic)obj).color = new Color(0f, 0f, 0f, 0f); ((Graphic)obj).raycastTarget = true; _content = UiFactory.Node("Content", (Transform)(object)val2); _content.anchorMin = new Vector2(0f, 1f); _content.anchorMax = new Vector2(1f, 1f); _content.pivot = new Vector2(0.5f, 1f); _content.anchoredPosition = new Vector2(0f, -4f); _content.sizeDelta = new Vector2(-20f, 100f); VerticalLayoutGroup obj2 = ((Component)_content).gameObject.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 8f; ((LayoutGroup)obj2).padding = new RectOffset(4, 4, 4, 4); ContentSizeFitter obj3 = ((Component)_content).gameObject.AddComponent<ContentSizeFitter>(); obj3.horizontalFit = (FitMode)0; obj3.verticalFit = (FitMode)2; _scroll.viewport = val2; _scroll.content = _content; } private static void AutoFitTranscript(RectTransform scrollRt, RectTransform panel) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) try { Canvas.ForceUpdateCanvases(); Rect rect = panel.rect; float yMax = ((Rect)(ref rect)).yMax; rect = panel.rect; float yMin = ((Rect)(ref rect)).yMin; float num = yMax - 64f; float num2 = yMin + 110f; Text[] componentsInChildren = ((Component)panel).GetComponentsInChildren<Text>(true); foreach (Text val in componentsInChildren) { if (((Object)((Component)val).gameObject).name.ToLowerInvariant().IndexOf("title") >= 0) { Bounds val2 = RectTransformUtility.CalculateRelativeRectTransformBounds((Transform)(object)panel, (Transform)(object)((Graphic)val).rectTransform); num = ((Bounds)(ref val2)).min.y - 8f; break; } } InputField componentInChildren = ((Component)panel).GetComponentInChildren<InputField>(true); if ((Object)(object)componentInChildren != (Object)null) { Transform transform = ((Component)componentInChildren).transform; Bounds val3 = RectTransformUtility.CalculateRelativeRectTransformBounds((Transform)(object)panel, (transform is RectTransform) ? transform : null); num2 = ((Bounds)(ref val3)).max.y + 8f; } if (num - num2 < 40f) { num = yMax - 64f; num2 = yMin + 110f; } scrollRt.offsetMax = new Vector2(scrollRt.offsetMax.x, 0f - (yMax - num)); scrollRt.offsetMin = new Vector2(scrollRt.offsetMin.x, num2 - yMin); ManualLogSource log = Plugin.Log; rect = scrollRt.rect; log.LogInfo((object)$"[UI] 正文区自动贴合:高 {((Rect)(ref rect)).height:0}px。"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("正文区自动贴合失败,使用兜底边距:" + ex.Message)); } } private void BuildInputBar(Font font) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) RectTransform val = UiFactory.Node("InputBar", (Transform)(object)_panel); UiFactory.BottomBar(val, 38f); RectTransform val2 = UiFactory.Node("Input", (Transform)(object)val); UiFactory.Stretch(val2, 8f, 3f, 8f, 5f); _inputImage = UiFactory.AddPanel(val2, DefaultInputBg); Image inputImage = _inputImage; RectTransform rt = UiFactory.Node("Text", (Transform)(object)val2); UiFactory.Stretch(rt, 8f, 0f, 8f); Text val3 = UiFactory.AddLabel(rt, font, _fontSize, _textMain, (TextAnchor)3); val3.supportRichText = false; val3.horizontalOverflow = (HorizontalWrapMode)1; RectTransform rt2 = UiFactory.Node("Placeholder", (Transform)(object)val2); UiFactory.Stretch(rt2, 8f, 0f, 8f); Text val4 = UiFactory.AddLabel(rt2, font, _fontSize, _textDim, (TextAnchor)3); val4.supportRichText = false; val4.horizontalOverflow = (HorizontalWrapMode)1; val4.text = Strings.Get("input.placeholder"); _authoredPlaceholder = val4.text; _input = ((Component)val2).gameObject.AddComponent<InputField>(); _input.textComponent = val3; _input.placeholder = (Graphic)(object)val4; ((Selectable)_input).targetGraphic = (Graphic)(object)inputImage; _input.lineType = (LineType)0; _input.characterLimit = 2000; ((UnityEvent<string>)(object)_input.onEndEdit).AddListener((UnityAction<string>)OnInputEndEdit); } public void ApplyStyle(UiStyle style) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) if (style == null || (Object)(object)_root == (Object)null) { return; } if (style.HasText) { _textMain = style.TextMain; _textDim = style.TextDim; _accent = style.Accent; } if ((Object)(object)style.Font != (Object)null) { _bodyFont = style.Font; } ApplySoftTextMaterials(); Text[] componentsInChildren; if ((Object)(object)style.Font != (Object)null) { componentsInChildren = _root.GetComponentsInChildren<Text>(true); foreach (Text val in componentsInChildren) { if (!_titleFromPrefab || val != _titleText) { ApplyBodyFont(val); } } } TextIconMapping mapping = TryGetPreferredIconMapping(); foreach (Item item in _items) { if (!((Object)(object)item.Label == (Object)null)) { if (item.Kind == LineKind.System) { ((Graphic)item.Label).color = _textDim; } else if (item.Kind == LineKind.Assistant && !item.FromPrefab) { ((Graphic)item.Label).color = _textMain; } AssignIconMapping(item.Label, mapping); } } if ((Object)(object)_statusText != (Object)null) { ((Graphic)_statusText).color = _textDim; } if ((Object)(object)_chatIndexTitle != (Object)null) { ((Graphic)_chatIndexTitle).color = _accent; } if ((Object)(object)_chatIndexEmpty != (Object)null) { ((Graphic)_chatIndexEmpty).color = _textDim; } RefreshIndexSelection(); if (_fromPrefab) { return; } if ((Object)(object)_panelImage != (Object)null) { style.ApplyPanel(_panelImage); } if ((Object)(object)_frameImage != (Object)null) { style.ApplyFrame(_frameImage); } if ((Object)(object)_glassImage != (Object)null) { style.ApplyGlass(_glassImage); } if ((Object)(object)_headerImage != (Object)null) { UiStyle.ApplyHeader(_headerImage); } if ((Object)(object)_inputImage != (Object)null) { style.ApplyInput(_inputImage); } componentsInChildren = _root.GetComponentsInChildren<Text>(true); foreach (Text val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)_transcript) && !((Object)(object)val2 == (Object)(object)_statusText)) { ((Graphic)val2).color = ((((Object)((Component)val2).gameObject).name == "Placeholder") ? _textDim : _textMain); } } } public void SetOpen(bool open) { if ((Object)(object)_root == (Object)null) { return; } if (open && !GameRefs.IsInGame) { Plugin.Log.LogInfo((object)"[UI] 不在游戏内,拒绝打开聊天窗"); return; } IsOpen = open; _root.SetActive(open); if (!open) { _wantInputFocus = false; _textMaterialRebound = false; } ApplyOpenState(open); if (open) { EnsureIconMappings(); } } private static void SeedInputCharColors(InputField f, string why) { if ((Object)(object)f == (Object)null) { return; } try { Color[] colorPaletteText = Configs.builtin.colorPaletteText; if (colorPaletteText != null && colorPaletteText.Length != 0) { f.m_CharColorsMapping = colorPaletteText; } int num = Mathf.Max(256, ((f.text != null) ? f.text.Length : 0) + 128); short[] array = f.m_CharColors; if (array == null || array.Length < num) { array = new short[num]; } for (int i = 0; i < array.Length; i++) { array[i] = -1; } f.m_CharColors = array; Plugin.Log.LogInfo((object)$"[UI] 输入框逐字符颜色已重置为默认色({array.Length} 槽,{why})。"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("输入框颜色表重置失败:" + ex.Message)); } } private static void RebindInputTextMaterial(Text t, string why) { if ((Object)(object)t == (Object)null) { return; } try { ((Graphic)t).SetMaterialDirty(); CanvasRenderer canvasRenderer = ((Graphic)t).canvasRenderer; if ((Object)(object)canvasRenderer != (Object)null) { Material materialForRendering = ((Graphic)t).materialForRendering; if ((Object)(object)materialForRendering != (Object)null) { canvasRenderer.materialCount = 1; canvasRenderer.SetMaterial(materialForRendering, 0); canvasRenderer.SetTexture(((Graphic)t).mainTexture); } } Canvas.ForceUpdateCanvases(); Plugin.Log.LogInfo((object)("[UI] 输入框 Text 材质已重新绑定(" + why + ";mat=" + (((Object)(object)((Graphic)t).materialForRendering != (Object)null) ? ((Object)((Graphic)t).materialForRendering).name : "null") + ")")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("输入框 Text 材质重绑失败:" + ex.Message)); } } private void EnsureInputCharColorHeadroom() { InputField input = _input; if ((Object)(object)input == (Object)null) { return; } int num = ((input.text != null) ? input.text.Length : 0) + 128; short[] charColors = input.m_CharColors; if (charColors != null && charColors.Length >= num) { return; } try { int num2 = Mathf.Max(256, num); short[] array = new short[num2]; for (int i = 0; i < num2; i++) { array[i] = -1; } if (charColors != null) { Array.Copy(charColors, array, Mathf.Min(charColors.Length, num2)); } input.m_CharColors = array; } catch (Exception ex) { Plugin.Log.LogWarning((object)("输入框颜色表扩容失败:" + ex.Message)); } } private void ApplyOpenState(bool open) { IsOpen = open; if (!open) { _wantInputFocus = false; } if (open) { _savedInputing = GameRefs.SetTextInputActive(active: true); UiFactory.EnsureEventSystem(); SeedInputCharColors(_input, "开窗"); if ((Object)(object)_input != (Object)null) { RebindInputTextMaterial(_input.textComponent, "开窗"); } if (_autoFocusInput || _keyEntryMode) { FocusInput(); } EnsureThinkingComboText(); EnsureModelComboText(); ScrollToBottomAfterContentChange(); } else { ClosePickers(); if ((Object)(object)_input != (Object)null) { _input.DeactivateInputField(true); _input.text = string.Empty; } GameRefs.SetTextInputActive(_savedInputing); } } private static void ClosePickers() { try { if (UISignalTagPicker.isOpened) { UISignalTagPicker.Close(); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("关闭图标选择器失败:" + ex.Message)); } try { if (UISimpleColorPicker.isOpened) { UISimpleColorPicker.Close(); } } catch (Exception ex2) { Plugin.Log.LogWarning((object)("关闭取色器失败:" + ex2.Message)); } } private static void CopyScalerSettings(CanvasScaler target, UIRoot uiRoot) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) try { CanvasScaler val = null; if ((Object)(object)uiRoot.overlayCanvas != (Object)null) { val = ((Component)uiRoot.overlayCanvas).GetComponent<CanvasScaler>(); } if ((Object)(object)val == (Object)null && (Object)(object)uiRoot.overlayCanvasTop != (Object)null) { val = ((Component)uiRoot.overlayCanvasTop).GetComponent<CanvasScaler>(); } if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"未找到游戏的 CanvasScaler,界面缩放将使用 Unity 默认值。"); return; } target.uiScaleMode = val.uiScaleMode; target.referenceResolution = val.referenceResolution; target.screenMatchMode = val.screenMatchMode; target.matchWidthOrHeight = val.matchWidthOrHeight; target.referencePixelsPerUnit = val.referencePixelsPerUnit; _scalerSource = ((Object)((Component)val).gameObject).name; } catch (Exception ex) { Plugin.Log.LogWarning((object)("复制 CanvasScaler 失败:" + ex.Message)); } } public string DescribeVisibility() { //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root == (Object)null) { return "root=null"; } StringBuilder stringBuilder = new StringBuilder(200); stringBuilder.Append("activeSelf=").Append(_root.activeSelf); stringBuilder.Append(" activeInHierarchy=").Append(_root.activeInHierarchy); Transform parent = _root.transform.parent; int num = 0; while ((Object)(object)parent != (Object)null && num < 6) { stringBuilder.Append(" < ").Append(((Object)parent).name).Append("[active=") .Append(((Component)parent).gameObject.activeInHierarchy); Canvas component = ((Component)parent).GetComponent<Canvas>(); if ((Object)(object)component != (Object)null) { stringBuilder.Append(" canvas.enabled=").Append(((Behaviour)component).enabled).Append(" order=") .Append(component.sortingOrder) .Append(" scale=") .Append(component.scaleFactor.ToString("0.##")); } CanvasGroup component2 = ((Component)parent).GetComponent<CanvasGroup>(); if ((Object)(object)component2 != (Object)null) { stringBuilder.Append(" group.alpha=").Append(component2.alpha.ToString("0.##")).Append(" interactable=") .Append(component2.interactable); } stringBuilder.Append(']'); parent = parent.parent; num++; } Canvas component3 = _root.GetComponent<Canvas>(); Rect val; if ((Object)(object)component3 != (Object)null) { StringBuilder stringBuilder2 = stringBuilder.Append(" canvasPixelRect="); val = component3.pixelRect; StringBuilder stringBuilder3 = stringBuilder2.Append(((Rect)(ref val)).width.ToString("0")).Append('x'); val = component3.pixelRect; stringBuilder3.Append(((Rect)(ref val)).height.ToString("0")); stringBuilder.Append(" canvasScaleFactor=").Append(component3.scaleFactor.ToString("0.##")); stringBuilder.Append(" canvasSorting=").Append(component3.sortingOrder); } RectTransform component4 = _root.GetComponent<RectTransform>(); if ((Object)(object)component4 != (Object)null) { StringBuilder stringBuilder4 = stringBuilder.Append(" canvasRect="); val = component4.rect; StringBuilder stringBuilder5 = stringBuilder4.Append(((Rect)(ref val)).width.ToString("0")).Append('x'); val = component4.rect; stringBuilder5.Append(((Rect)(ref val)).height.ToString("0")); stringBuilder.Append(" canvasPivot=").Append(component4.pivot); } stringBuilder.Append(" screen=").Append(Screen.width).Append('x') .Append(Screen.height); if ((Object)(object)_panel != (Object)null) { StringBuilder stringBuilder6 = stringBuilder.Append(" panelRect="); val = _panel.rect; StringBuilder stringBuilder7 = stringBuilder6.Append(((Rect)(ref val)).width.ToString("0")).Append('x'); val = _panel.rect; stringBuilder7.Append(((Rect)(ref val)).height.ToString("0")); stringBuilder.Append(" panelAnchored=").Append(_panel.anchoredPosition); Vector3[] array = (Vector3[])(object)new Vector3[4]; _panel.GetWorldCorners(array); stringBuilder.Append(" panelWorldBL=").Append(array[0].x.ToString("0")).Append(',') .Append(array[0].y.ToString("0")); stringBuilder.Append(" TR=").Append(array[2].x.ToString("0")).Append(',') .Append(array[2].y.ToString("0")); } return stringBuilder.ToString(); } public void SetStatus(string text, Color? color = null) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_statusText == (Object)null)) { _statusText.text = text ?? string.Empty; ((Graphic)_statusText).color = (Color)(((??)color) ?? _textDim); } } public void AppendLine(string speaker, string text, string gameTime = null) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (text != null) { string text2 = (string.IsNullOrEmpty(speaker) ? string.Empty : ("<color=#" + ColorUtility.ToHtmlStringRGB(_accent) + ">" + Escape(speaker) + "</color> ")); AddMessage(LineKind.Assistant, text2 + text, gameTime); _awaitingResponse = false; } } public void AppendUser(string text, long timestampMs = 0L, string gameTime = null) { if (text != null) { if (_thinking != null) { EndThinking(); } _currentTurnId = ++_nextTurnId; _awaitingResponse = true; AddMessage(LineKind.User, text, gameTime); AddTurn(_currentTurnId, text, timestampMs); } } public void AppendSystem(string text) { if (text != null) { AddMessage(LineKind.System, text); _awaitingResponse = false; } } public void AppendBlueprintCard(BlueprintCardInfo card) { if (card == null) { return; } if (string.IsNullOrEmpty(card.CreatedAt)) { card.CreatedAt = DateTime.Now.ToString("yyyy-MM-dd"); } if ((Object)(object)_content == (Object)null) { _lines.Add(new Line { Kind = LineKind.Blueprint, Text = card.DisplayTitle, TurnId = _currentTurnId, Cards = new List<BlueprintCardInfo> { card } }); TrimHistory(); _dirty = true; return; } if ((Object)(object)_replyTemplate != (Object)null) { int num = FindReplyItemForCard(); if (num >= 0 && num < _items.Count && _items[num].Reply != null) { Item item = _items[num]; if (AddCard(item.Reply, card) != null) { if (_streamItem == num && _stream.Length == 0 && !_awaitingResponse && _thinking == null) { _streamItem = -1; } int num2 = FindLineIndex(item.Go); if (num2 >= 0) { Line value = _lines[num2]; if (value.Cards == null) { value.Cards = new List<BlueprintCardInfo>(); } value.Cards.Add(card); _lines[num2] = value; } else { _lines.Add(new Line { Kind = LineKind.Assistant, Text = string.Empty, TurnId = _currentTurnId, Go = item.Go, Cards = new List<BlueprintCardInfo> { card }, Time = GameClock() }); } TrimHistory(); _dirty = true; ScrollToBottomAfterContentChange(); return; } } } GameObject val = CreateBlueprintCard(card); if (!((Object)(object)val == (Object)null)) { _lines.Add(new Line { Kind = LineKind.Blueprint, Text = card.DisplayTitle, TurnId = _currentTurnId, Go = val, Cards = new List<BlueprintCardInfo> { card } }); TrimHistory(); _dirty = true; ScrollToBottomAfterContentChange(); } } private CardView AddCard(ReplyView reply, BlueprintCardInfo card) { if (reply == null || (Object)(object)reply.CardTemplate == (Object)null || (Object)(object)reply.BlueprintCards == (Object)null || card == null) { return null; } GameObject val = Object.Instantiate<GameObject>(((Component)reply.CardTemplate).gameObject, (Transform)(object)reply.BlueprintCards, false); ((Object)val).name = "blueprint-card-" + ++_itemSeq; val.SetActive(true); CardView cardView = BindCardView(val); if (cardView == null) { Object.Destroy((Object)(object)val); return null; } ((Component)reply.BlueprintCards).gameObject.SetActive(true); cardView.Card = card; ApplyCard(cardView, card); reply.CardViews.Add(cardView); return cardView; } private void AddCards(ReplyView reply, List<BlueprintCardInfo> cards) { if (reply == null || cards == null) { return; } for (int i = 0; i < cards.Count; i++) { if (cards[i] != null) { AddCard(reply, cards[i]); } } } private CardView BindCardView(GameObject go) { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Expected O, but got Unknown //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Expected O, but got Unknown if ((Object)(object)go == (Object)null) { return null; } Transform transform = go.transform; CardView view = new CardView { Go = go }; Transform val = transform.Find("thumb"); if ((Object)(object)val != (Object)null) { Transform val2 = val.Find("icon"); view.ThumbIconRoot = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null); view.ThumbIcon = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<Image>() : null); Transform val3 = val.Find("fallback"); view.ThumbFallback = (((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : null); view.ThumbLabel = FindChildText(val, "label"); } view.Name = FindChildText(transform, "content/name"); view.Description = FindChildText(transform, "content/desc-mask/description"); view.Meta = FindChildText(transform, "content/meta"); view.CardButton = go.GetComponent<Button>(); if ((Object)(object)view.CardButton != (Object)null) { ((UnityEventBase)view.CardButton.onClick).RemoveAllListeners(); ((UnityEvent)view.CardButton.onClick).AddListener((UnityAction)delegate { RequestCardAction(view.Card, BlueprintCardAction.Inspect); }); } Transform val4 = transform.Find("content/use"); if ((Object)(object)val4 == (Object)null) { val4 = transform.Find("content/actions/use"); } if ((Object)(object)val4 != (Object)null) { view.UseButton = ((Component)val4).GetComponent<Button>(); view.UseLabel = FindChildText(val4, "label"); } Transform val5 = transform.Find("content/view"); if ((Object)(object)val5 == (Object)null) { val5 = transform.Find("content/actions/view"); } if ((Object)(object)val5 != (Object)null) { view.ViewButton = ((Component)val5).GetComponent<Button>(); view.ViewLabel = FindChildText(val5, "label"); } if ((Object)(object)view.ViewLabel != (Object)null) { view.ViewLabel.text = Strings.Get("blueprint.card.view"); } if ((Object)(object)view.UseLabel != (Object)null) { view.UseLabel.text = Strings.Get("blueprint.card.paste"); } if ((Object)(object)view.ViewButton != (Object)null) { ((UnityEventBase)view.ViewButton.onClick).RemoveAllListeners(); ((UnityEvent)view.ViewButton.onClick).AddListener((UnityAction)delegate { RequestCardAction(view.Card, BlueprintCardAction.Inspect); }); } if ((Object)(object)view.UseButton != (Object)null) { ((UnityEventBase)view.UseButton.onClick).RemoveAllListeners(); ((UnityEvent)view.UseButton.onClick).AddListener((UnityAction)delegate { RequestCardAction(view.Card, BlueprintCardAction.Paste); }); } return view; } private GameObject CreateBlueprintCard(BlueprintCardInfo card) { if ((Object)(object)_content == (Object)null || card == null) { return null; } int childCount = ((Transform)_content).childCount; try { return BuildBlueprintCard(card); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[UI] 蓝图卡片创建失败({card.FileName}):{arg}"); for (int num = ((Transform)_content).childCount - 1; num >= childCount; num--) { Transform child = ((Transform)_content).GetChild(num); if ((Object)(object)child != (Object)null) { Object.Destroy((Object)(object)((Component)child).gameObject); } } return null; } } private GameObject BuildBlueprintCard(BlueprintCardInfo card) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Expected O, but got Unknown //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0513: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Unknown result type (might be due to invalid IL or missing references) //IL_060e: Unknown result type (might be due to invalid IL or missing references) //IL_0746: Unknown result type (might be due to invalid IL or missing references) //IL_0750: Expected O, but got Unknown //IL_07a3: Unknown result type (might be due to invalid IL or missing references) //IL_07df: Unknown result type (might be due to invalid IL or missing references) //IL_06cd: Unknown result type (might be due to invalid IL or missing references) int num = ++_itemSeq; RectTransform val = UiFactory.Node("blueprint-card-" + num, (Transform)(object)_content); val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(1f, 1f); val.pivot = new Vector2(0.5f, 1f); val.anchoredPosition = Vector2.zero; val.sizeDelta = Vector2.zero; Image obj = ((Component)val).gameObject.AddComponent<Image>(); ((Graphic)obj).color = new Color(0.38f, 0.85f, 1f, 0.07f); ((Graphic)obj).raycastTarget = false; VerticalLayoutGroup obj2 = ((Component)val).gameObject.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj2).padding = new RectOffset(10, 10, 8, 8); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 5f; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; ((LayoutGroup)obj2).childAlignment = (TextAnchor)0; RectTransform obj3 = UiFactory.Node("accent", (Transform)(object)val); obj3.anchorMin = new Vector2(0f, 0f); obj3.anchorMax = new Vector2(0f, 1f); obj3.pivot = new Vector2(0f, 0.5f); obj3.sizeDelta = new Vector2(2f, 0f); obj3.anchoredPosition = Vector2.zero; Image obj4 = ((Component)obj3).gameObject.AddComponent<Image>(); ((Graphic)obj4).color = new Color(_accent.r, _accent.g, _accent.b, 0.55f); ((Graphic)obj4).raycastTarget = false; ((Component)obj3).gameObject.AddComponent<LayoutElement>().ignoreLayout = true; RectTra