Decompiled source of IcarusII v0.3.1

plugins/IcarusII/IcarusII.dll

Decompiled a day ago
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