PageVersionMod.xaml.vb 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. Public Class PageVersionMod
  2. #Region "初始化"
  3. Private IsLoad As Boolean = False
  4. Public Sub PageOther_Loaded() Handles Me.Loaded
  5. If FrmMain.PageLast.Page <> FormMain.PageType.CompDetail Then PanBack.ScrollToHome()
  6. AniControlEnabled += 1
  7. SelectedMods.Clear()
  8. RefreshList()
  9. ChangeAllSelected(False)
  10. AniControlEnabled -= 1
  11. '非重复加载部分
  12. If IsLoad Then Exit Sub
  13. IsLoad = True
  14. #If DEBUG Then
  15. BtnManageCheck.Visibility = Visibility.Visible
  16. #End If
  17. End Sub
  18. ''' <summary>
  19. ''' 刷新 Mod 列表。
  20. ''' </summary>
  21. Public Sub RefreshList(Optional ForceReload As Boolean = False)
  22. If McModLoader.State = LoadState.Loading Then Exit Sub
  23. If LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", If(ForceReload, LoaderFolderRunType.ForceRun, LoaderFolderRunType.RunOnUpdated)) Then
  24. Log("[System] 已刷新 Mod 列表")
  25. PanBack.ScrollToHome()
  26. SearchBox.Text = ""
  27. End If
  28. End Sub
  29. Private Sub LoaderInit() Handles Me.Initialized
  30. PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, McModLoader, AddressOf LoadUIFromLoaderOutput, AutoRun:=False)
  31. End Sub
  32. Private Sub Load_Click(sender As Object, e As MouseButtonEventArgs) Handles Load.Click
  33. If McModLoader.State = LoadState.Failed Then
  34. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.ForceRun)
  35. End If
  36. End Sub
  37. #End Region
  38. #Region "UI 化"
  39. ''' <summary>
  40. ''' 已加载的 Mod UI 缓存,不确保按显示顺序排列。Key 为 Mod 的 RawFileName。
  41. ''' </summary>
  42. Public ModItems As New Dictionary(Of String, MyLocalModItem)
  43. ''' <summary>
  44. ''' 将加载器结果的 Mod 列表加载为 UI。
  45. ''' </summary>
  46. Private Sub LoadUIFromLoaderOutput()
  47. Dim Mods As List(Of McMod) = McModLoader.Output
  48. Try
  49. '判断应该显示哪一个页面
  50. If Mods.Any() Then
  51. PanBack.Visibility = Visibility.Visible
  52. PanEmpty.Visibility = Visibility.Collapsed
  53. Else
  54. PanEmpty.Visibility = Visibility.Visible
  55. PanBack.Visibility = Visibility.Collapsed
  56. Exit Sub
  57. End If
  58. SearchBox.Text = ""
  59. '输出结果
  60. ModItems.Clear()
  61. For Each ModEntity As McMod In Mods
  62. ModItems(ModEntity.RawFileName) = McModListItem(ModEntity)
  63. Next
  64. RefreshResult(Mods)
  65. Catch ex As Exception
  66. Log(ex, "加载 Mod 列表 UI 失败", LogLevel.Feedback)
  67. End Try
  68. End Sub
  69. Private Function McModListItem(Entry As McMod) As MyLocalModItem
  70. AniControlEnabled += 1
  71. Dim NewItem As New MyLocalModItem With {.SnapsToDevicePixels = True, .Entry = Entry,
  72. .ButtonHandler = AddressOf McModContent, .Checked = SelectedMods.Contains(Entry.RawFileName)}
  73. AddHandler Entry.OnGetCompProject, AddressOf NewItem.Refresh
  74. NewItem.Refresh()
  75. AniControlEnabled -= 1
  76. Return NewItem
  77. End Function
  78. Private Sub McModContent(sender As MyLocalModItem, e As EventArgs)
  79. '点击事件
  80. AddHandler sender.Changed, AddressOf CheckChanged
  81. AddHandler sender.Click, Sub(ss As MyLocalModItem, ee As EventArgs) ss.Checked = Not ss.Checked
  82. '图标按钮
  83. Dim BtnOpen As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonOpen, .Tag = sender}
  84. BtnOpen.ToolTip = "打开文件位置"
  85. ToolTipService.SetPlacement(BtnOpen, Primitives.PlacementMode.Center)
  86. ToolTipService.SetVerticalOffset(BtnOpen, 30)
  87. ToolTipService.SetHorizontalOffset(BtnOpen, 2)
  88. AddHandler BtnOpen.Click, AddressOf Open_Click
  89. Dim BtnCont As New MyIconButton With {.LogoScale = 1, .Logo = Logo.IconButtonInfo, .Tag = sender}
  90. BtnCont.ToolTip = "详情"
  91. ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
  92. ToolTipService.SetVerticalOffset(BtnCont, 30)
  93. ToolTipService.SetHorizontalOffset(BtnCont, 2)
  94. AddHandler BtnCont.Click, AddressOf Info_Click
  95. AddHandler sender.MouseRightButtonDown, AddressOf Info_Click
  96. Dim BtnDelete As New MyIconButton With {.LogoScale = 1, .Logo = Logo.IconButtonDelete, .Tag = sender}
  97. BtnDelete.ToolTip = "删除"
  98. ToolTipService.SetPlacement(BtnDelete, Primitives.PlacementMode.Center)
  99. ToolTipService.SetVerticalOffset(BtnDelete, 30)
  100. ToolTipService.SetHorizontalOffset(BtnDelete, 2)
  101. AddHandler BtnDelete.Click, AddressOf Delete_Click
  102. Dim BtnED As New MyIconButton With {.LogoScale = 1, .Logo = If(sender.Entry.State = McMod.McModState.Fine,
  103. "M508 990.4c-261.6 0-474.4-212-474.4-474.4S246.4 41.6 508 41.6s474.4 212 474.4 474.4S769.6 990.4 508 990.4zM508 136.8c-209.6 0-379.2 169.6-379.2 379.2 0 209.6 169.6 379.2 379.2 379.2s379.2-169.6 379.2-379.2C887.2 306.4 717.6 136.8 508 136.8zM697.6 563.2 318.4 563.2c-26.4 0-47.2-21.6-47.2-47.2 0-26.4 21.6-47.2 47.2-47.2l379.2 0c26.4 0 47.2 21.6 47.2 47.2C744.8 542.4 724 563.2 697.6 563.2z",
  104. "M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z"),
  105. .Tag = sender}
  106. BtnED.ToolTip = If(sender.Entry.State = McMod.McModState.Fine, "禁用", "启用")
  107. ToolTipService.SetPlacement(BtnED, Primitives.PlacementMode.Center)
  108. ToolTipService.SetVerticalOffset(BtnED, 30)
  109. ToolTipService.SetHorizontalOffset(BtnED, 2)
  110. AddHandler BtnED.Click, AddressOf ED_Click
  111. If sender.Entry.State = McMod.McModState.Unavaliable Then
  112. sender.Buttons = {BtnCont, BtnOpen, BtnDelete}
  113. Else
  114. sender.Buttons = {BtnCont, BtnOpen, BtnED, BtnDelete}
  115. End If
  116. End Sub
  117. ''' <summary>
  118. ''' 刷新结果显示。
  119. ''' </summary>
  120. Private Sub RefreshResult(Mods As List(Of McMod))
  121. PanList.Children.Clear()
  122. For Each TargetMod In Mods
  123. PanList.Children.Add(ModItems(TargetMod.RawFileName))
  124. Next
  125. RefreshTitle()
  126. End Sub
  127. ''' <summary>
  128. ''' 刷新卡片标题。
  129. ''' </summary>
  130. Private Sub RefreshTitle()
  131. Dim Mods = PanList.Children.Cast(Of MyLocalModItem).Select(Function(i) i.Entry).ToList
  132. Dim Counter = {0, 0, 0}
  133. For Each ModEntity As McMod In Mods
  134. Counter(ModEntity.State) += 1
  135. Next
  136. Dim TypeList As New List(Of String)
  137. If Counter(McMod.McModState.Disabled) > 0 Then TypeList.Add("禁用 " & Counter(McMod.McModState.Disabled))
  138. If Counter(McMod.McModState.Unavaliable) > 0 Then TypeList.Add("错误 " & Counter(McMod.McModState.Unavaliable))
  139. If Counter(McMod.McModState.Fine) > 0 Then TypeList.Insert(0, If(TypeList.Any, "启用 ", "") & Counter(McMod.McModState.Fine))
  140. If Not IsSearching Then
  141. PanListBack.Title = "Mod 列表 (" & Join(TypeList, ",") & ")"
  142. ElseIf TypeList.Any() Then
  143. PanListBack.Title = "搜索结果 (" & Join(TypeList, ",") & ")"
  144. Else
  145. PanListBack.Title = "无搜索结果"
  146. End If
  147. PanList.Visibility = If(Mods.Any(), Visibility.Visible, Visibility.Collapsed)
  148. End Sub
  149. #End Region
  150. #Region "管理"
  151. ''' <summary>
  152. ''' 打开 Mods 文件夹。
  153. ''' </summary>
  154. Private Sub BtnManageOpen_Click(sender As Object, e As EventArgs) Handles BtnManageOpen.Click, BtnHintOpen.Click
  155. Try
  156. Directory.CreateDirectory(PageVersionLeft.Version.PathIndie & "mods\")
  157. OpenExplorer("""" & PageVersionLeft.Version.PathIndie & "mods\""")
  158. Catch ex As Exception
  159. Log(ex, "打开 Mods 文件夹失败", LogLevel.Msgbox)
  160. End Try
  161. End Sub
  162. #If DEBUG Then
  163. ''' <summary>
  164. ''' 检查 Mod。
  165. ''' </summary>
  166. Private Sub BtnManageCheck_Click(sender As Object, e As EventArgs) Handles BtnManageCheck.Click
  167. Try
  168. Dim Result = McModCheck(PageVersionLeft.Version, McModLoader.Output)
  169. If Result.Count > 0 Then
  170. MyMsgBox(Join(Result, vbCrLf & vbCrLf), "Mod 检查结果")
  171. Else
  172. Hint("Mod 检查完成,未发现任何问题!", HintType.Finish)
  173. End If
  174. Catch ex As Exception
  175. Log(ex, "进行 Mod 检查时出错", LogLevel.Feedback)
  176. End Try
  177. End Sub
  178. #End If
  179. ''' <summary>
  180. ''' 全选。
  181. ''' </summary>
  182. Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click
  183. If SelectedMods.Count < PanList.Children.Count Then
  184. ChangeAllSelected(True)
  185. Else
  186. ChangeAllSelected(False)
  187. End If
  188. End Sub
  189. ''' <summary>
  190. ''' 安装 Mod。
  191. ''' </summary>
  192. Private Sub BtnManageInstall_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageInstall.Click
  193. Hint("将 Mod 文件直接拖入 PCL 窗口即可安装!")
  194. End Sub
  195. #End Region
  196. #Region "选择"
  197. '选择的 Mod 的路径(不含 .disabled)
  198. Public SelectedMods As New List(Of String)
  199. '单项切换选择状态
  200. Public Sub CheckChanged(sender As MyLocalModItem, e As RouteEventArgs)
  201. If AniControlEnabled <> 0 Then Return
  202. '更新选择了的内容
  203. Dim SelectedKey As String = sender.Entry.RawFileName
  204. If sender.Checked Then
  205. If Not SelectedMods.Contains(SelectedKey) Then SelectedMods.Add(SelectedKey)
  206. Else
  207. SelectedMods.Remove(SelectedKey)
  208. End If
  209. '更新下边栏 UI
  210. RefreshBottomBar()
  211. End Sub
  212. '改变下边栏状态
  213. Private ShownCount As Integer = 0
  214. Private Sub RefreshBottomBar()
  215. '计数
  216. Dim NewCount As Integer = SelectedMods.Count
  217. Dim Selected = NewCount > 0
  218. If Selected Then LabSelect.Text = $"已选择 {NewCount} 个文件" '取消所有选择时不更新数字
  219. '按钮可用性
  220. If Selected Then
  221. Dim HasEnabled As Boolean = False
  222. Dim HasDisabled As Boolean = False
  223. For Each ModEntity In McModLoader.Output
  224. If SelectedMods.Contains(ModEntity.RawFileName) Then
  225. If ModEntity.State = McMod.McModState.Fine Then
  226. HasEnabled = True
  227. ElseIf ModEntity.State = McMod.McModState.Disabled Then
  228. HasDisabled = True
  229. End If
  230. End If
  231. Next
  232. BtnSelectDisable.IsEnabled = HasEnabled
  233. BtnSelectEnable.IsEnabled = HasDisabled
  234. End If
  235. '更新显示状态
  236. CardSelect.IsHitTestVisible = Selected
  237. If AniControlEnabled = 0 Then
  238. If Selected Then
  239. '仅在数量增加时播放出现/跳跃动画
  240. If ShownCount >= NewCount Then
  241. ShownCount = NewCount
  242. Return
  243. Else
  244. ShownCount = NewCount
  245. End If
  246. '出现/跳跃动画
  247. CardSelect.Visibility = Visibility.Visible
  248. AniStart({
  249. AaOpacity(CardSelect, 1 - CardSelect.Opacity, 60),
  250. AaTranslateY(CardSelect, -27 - TransSelect.Y, 120, Ease:=New AniEaseOutFluent(AniEasePower.Weak)),
  251. AaTranslateY(CardSelect, 3, 150, 120, Ease:=New AniEaseInoutFluent(AniEasePower.Weak)),
  252. AaTranslateY(CardSelect, -1, 90, 270, Ease:=New AniEaseInoutFluent(AniEasePower.Weak))
  253. }, "Mod Sidebar")
  254. Else
  255. '不重复播放隐藏动画
  256. If ShownCount = 0 Then Return
  257. ShownCount = 0
  258. '隐藏动画
  259. AniStart({
  260. AaOpacity(CardSelect, -CardSelect.Opacity, 90),
  261. AaTranslateY(CardSelect, -10 - TransSelect.Y, 90, Ease:=New AniEaseInFluent(AniEasePower.Weak)),
  262. AaCode(Sub() CardSelect.Visibility = Visibility.Collapsed, After:=True)
  263. }, "Mod Sidebar")
  264. End If
  265. Else
  266. AniStop("Mod Sidebar")
  267. ShownCount = NewCount
  268. If Selected Then
  269. CardSelect.Visibility = Visibility.Visible
  270. CardSelect.Opacity = 1
  271. TransSelect.Y = -25
  272. Else
  273. CardSelect.Visibility = Visibility.Collapsed
  274. CardSelect.Opacity = 0
  275. TransSelect.Y = -10
  276. End If
  277. End If
  278. End Sub
  279. '切换所有项的选择状态
  280. Private Sub ChangeAllSelected(Value As Boolean)
  281. AniControlEnabled += 1
  282. SelectedMods.Clear()
  283. For Each Item As MyLocalModItem In PanList.Children
  284. Item.Checked = Value
  285. If Value Then SelectedMods.Add(Item.Entry.RawFileName)
  286. Next
  287. AniControlEnabled -= 1
  288. '更新下边栏 UI
  289. RefreshBottomBar()
  290. End Sub
  291. Private Sub UnselectedAllWithAnimation() Handles Load.StateChanged, Me.PageExit
  292. Dim CacheAniControlEnabled = AniControlEnabled
  293. AniControlEnabled = 0
  294. ChangeAllSelected(False)
  295. AniControlEnabled += CacheAniControlEnabled
  296. End Sub
  297. Private Sub PageVersionMod_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
  298. If My.Computer.Keyboard.CtrlKeyDown AndAlso e.Key = Key.A Then ChangeAllSelected(True)
  299. End Sub
  300. #End Region
  301. #Region "下边栏"
  302. '启用 / 禁用
  303. Private Sub BtnSelectED_Click(sender As MyIconTextButton, e As RouteEventArgs) Handles BtnSelectEnable.Click, BtnSelectDisable.Click
  304. EDMods(McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)),
  305. Not sender.Equals(BtnSelectDisable))
  306. ChangeAllSelected(False)
  307. End Sub
  308. Private Sub EDMods(ModList As IEnumerable(Of McMod), IsEnable As Boolean)
  309. Dim IsSuccessful As Boolean = True
  310. For Each ModEntity In ModList.ToList
  311. Dim NewPath As String = Nothing
  312. If ModEntity.State = McMod.McModState.Fine AndAlso Not IsEnable Then
  313. '禁用
  314. NewPath = ModEntity.Path & ".disabled"
  315. ElseIf ModEntity.State = McMod.McModState.Disabled AndAlso IsEnable Then
  316. '启用
  317. NewPath = ModEntity.Path.Replace(".disabled", "").Replace(".old", "")
  318. Else
  319. Continue For
  320. End If
  321. '重命名
  322. Try
  323. If File.Exists(NewPath) AndAlso Not File.Exists(ModEntity.Path) Then Continue For '因为未知原因 Mod 的状态已经切换完了
  324. File.Delete(NewPath)
  325. FileSystem.Rename(ModEntity.Path, NewPath)
  326. Catch ex As FileNotFoundException
  327. Log(ex, $"未找到需要重命名的 Mod({If(ModEntity.Path, "null")})", LogLevel.Feedback)
  328. RefreshList(True)
  329. Return
  330. Catch ex As Exception
  331. Log(ex, $"重命名 Mod 失败({If(ModEntity.Path, "null")})")
  332. IsSuccessful = False
  333. End Try
  334. '更改 Loader 中的列表
  335. Dim NewModEntity As New McMod(NewPath)
  336. NewModEntity.Comp = ModEntity.Comp
  337. Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity)
  338. McModLoader.Output.RemoveAt(IndexOfLoader)
  339. McModLoader.Output.Insert(IndexOfLoader, NewModEntity)
  340. '更改 UI 中的列表
  341. Dim NewItem As MyLocalModItem = McModListItem(NewModEntity)
  342. ModItems(ModEntity.RawFileName) = NewItem
  343. Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).FirstOrDefault(Function(i) i.Entry Is ModEntity))
  344. If IndexOfUi = -1 Then Continue For '因为未知原因 Mod 的状态已经切换完了
  345. PanList.Children.RemoveAt(IndexOfUi)
  346. PanList.Children.Insert(IndexOfUi, NewItem)
  347. Next
  348. RefreshTitle() '改变数量显示
  349. If Not IsSuccessful Then
  350. Hint("由于文件被占用,Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
  351. RefreshList(True)
  352. Else
  353. RefreshBottomBar()
  354. End If
  355. End Sub
  356. '删除
  357. Private Sub BtnSelectDelete_Click() Handles BtnSelectDelete.Click
  358. Dim DeleteList As List(Of McMod) = McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)).ToList()
  359. DeleteMods(DeleteList)
  360. End Sub
  361. Private Sub DeleteMods(ModList As IEnumerable(Of McMod))
  362. Try
  363. Dim IsSuccessful As Boolean = True
  364. Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
  365. For Each ModEntity In ModList
  366. '删除
  367. Try
  368. If IsShiftPressed Then
  369. File.Delete(ModEntity.Path)
  370. Else
  371. My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
  372. End If
  373. Catch ex As OperationCanceledException
  374. Log(ex, "删除 Mod 被主动取消")
  375. RefreshList(True)
  376. Return
  377. Catch ex As Exception
  378. Log(ex, $"删除 Mod 失败({ModEntity.Path})", LogLevel.Msgbox)
  379. IsSuccessful = False
  380. End Try
  381. '取消选中
  382. SelectedMods.Remove(ModEntity.RawFileName)
  383. '更改 Loader 和 UI 中的列表
  384. McModLoader.Output.Remove(ModEntity)
  385. ModItems.Remove(ModEntity.RawFileName)
  386. Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).First(Function(i) i.Entry Is ModEntity))
  387. PanList.Children.RemoveAt(IndexOfUi)
  388. Next
  389. RefreshTitle()
  390. If Not IsSuccessful Then
  391. Hint("由于文件被占用,Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
  392. RefreshList(True)
  393. ElseIf PanList.Children.Count = 0 Then
  394. RefreshList(True) '删除了全部文件
  395. Else
  396. RefreshBottomBar()
  397. End If
  398. '显示结果提示
  399. If Not IsSuccessful Then Exit Sub
  400. If IsShiftPressed Then
  401. If ModList.Count = 1 Then
  402. Hint($"已彻底删除 {ModList.Single.FileName}!", HintType.Finish)
  403. Else
  404. Hint($"已彻底删除 {ModList.Count} 个文件!", HintType.Finish)
  405. End If
  406. Else
  407. If ModList.Count = 1 Then
  408. Hint($"已将 {ModList.Single.FileName} 删除到回收站!", HintType.Finish)
  409. Else
  410. Hint($"已将 {ModList.Count} 个文件删除到回收站!", HintType.Finish)
  411. End If
  412. End If
  413. Catch ex As OperationCanceledException
  414. Log(ex, "删除 Mod 被主动取消")
  415. RefreshList(True)
  416. Catch ex As Exception
  417. Log(ex, "删除 Mod 出现未知错误", LogLevel.Feedback)
  418. RefreshList(True)
  419. End Try
  420. End Sub
  421. '取消选择
  422. Private Sub BtnSelectCancel_Click() Handles BtnSelectCancel.Click
  423. ChangeAllSelected(False)
  424. End Sub
  425. #End Region
  426. #Region "单个 Mod 项"
  427. '详情
  428. Public Sub Info_Click(sender As Object, e As EventArgs)
  429. Try
  430. Dim ModEntry As McMod = CType(If(TypeOf sender Is MyIconButton, sender.Tag, sender), MyLocalModItem).Entry
  431. '加载失败信息
  432. If ModEntry.State = McMod.McModState.Unavaliable Then
  433. MyMsgBox("无法读取此 Mod 的信息。" & vbCrLf & vbCrLf & "详细的错误信息:" & GetExceptionDetail(ModEntry.FileUnavailableReason), "Mod 读取失败")
  434. Return
  435. End If
  436. If ModEntry.Comp IsNot Nothing Then
  437. '跳转到 Mod 下载页面
  438. FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
  439. .Additional = {ModEntry.Comp, New List(Of String), PageVersionLeft.Version.Version.McName,
  440. If(PageVersionLeft.Version.Version.HasForge, CompModLoaderType.Forge, If(PageVersionLeft.Version.Version.HasFabric, CompModLoaderType.Fabric, CompModLoaderType.Any))}})
  441. Else
  442. '获取信息
  443. Dim ContentLines As New List(Of String)
  444. If ModEntry.Description IsNot Nothing Then ContentLines.Add(ModEntry.Description & vbCrLf)
  445. If ModEntry.Authors IsNot Nothing Then ContentLines.Add("作者:" & ModEntry.Authors)
  446. ContentLines.Add("文件:" & ModEntry.FileName & "(" & GetString(New FileInfo(ModEntry.Path).Length) & ")")
  447. If ModEntry.Version IsNot Nothing Then ContentLines.Add("版本:" & ModEntry.Version)
  448. Dim DebugInfo As New List(Of String)
  449. If ModEntry.ModId IsNot Nothing Then
  450. DebugInfo.Add("Mod ID:" & ModEntry.ModId)
  451. End If
  452. If ModEntry.Dependencies.Count > 0 Then
  453. DebugInfo.Add("依赖于:")
  454. For Each Dep In ModEntry.Dependencies
  455. DebugInfo.Add(" - " & Dep.Key & If(Dep.Value Is Nothing, "", ",版本:" & Dep.Value))
  456. Next
  457. End If
  458. If DebugInfo.Count > 0 Then
  459. ContentLines.Add("")
  460. ContentLines.AddRange(DebugInfo)
  461. End If
  462. '获取用于搜索的 Mod 名称
  463. Dim ModOriginalName As String = ModEntry.Name.Replace(" ", "+")
  464. Dim ModSearchName As String = ModOriginalName.Substring(0, 1)
  465. For i = 1 To ModOriginalName.Count - 1
  466. Dim IsLastLower As Boolean = ModOriginalName(i - 1).ToString.ToLower.Equals(ModOriginalName(i - 1).ToString)
  467. Dim IsCurrentLower As Boolean = ModOriginalName(i).ToString.ToLower.Equals(ModOriginalName(i).ToString)
  468. If IsLastLower AndAlso Not IsCurrentLower Then
  469. '上一个字母为小写,这一个字母为大写
  470. ModSearchName += "+"
  471. End If
  472. ModSearchName += ModOriginalName(i)
  473. Next
  474. ModSearchName = ModSearchName.Replace("++", "+").Replace("pti+Fine", "ptiFine")
  475. '显示
  476. If ModEntry.Url Is Nothing Then
  477. If MyMsgBox(Join(ContentLines, vbCrLf), ModEntry.Name, "百科搜索", "返回") = 1 Then
  478. OpenWebsite("https://www.mcmod.cn/s?key=" & ModSearchName & "&site=all&filter=0")
  479. End If
  480. Else
  481. Select Case MyMsgBox(Join(ContentLines, vbCrLf), ModEntry.Name, "打开官网", "百科搜索", "返回")
  482. Case 1
  483. OpenWebsite(ModEntry.Url)
  484. Case 2
  485. OpenWebsite("https://www.mcmod.cn/s?key=" & ModSearchName & "&site=all&filter=0")
  486. End Select
  487. End If
  488. End If
  489. Catch ex As Exception
  490. Log(ex, "获取 Mod 详情失败", LogLevel.Feedback)
  491. End Try
  492. End Sub
  493. '打开文件所在的位置
  494. Public Sub Open_Click(sender As MyIconButton, e As EventArgs)
  495. Try
  496. Dim ListItem As MyLocalModItem = sender.Tag
  497. OpenExplorer("/select,""" & ListItem.Entry.Path & """")
  498. Catch ex As Exception
  499. Log(ex, "打开 Mod 文件位置失败", LogLevel.Feedback)
  500. End Try
  501. End Sub
  502. '删除
  503. Public Sub Delete_Click(sender As MyIconButton, e As EventArgs)
  504. Dim ListItem As MyLocalModItem = sender.Tag
  505. DeleteMods({ListItem.Entry})
  506. End Sub
  507. '启用 / 禁用
  508. Public Sub ED_Click(sender As MyIconButton, e As EventArgs)
  509. Dim ListItem As MyLocalModItem = sender.Tag
  510. EDMods({ListItem.Entry}, ListItem.Entry.State = McMod.McModState.Disabled)
  511. End Sub
  512. #End Region
  513. #Region "搜索"
  514. Public ReadOnly Property IsSearching As Boolean
  515. Get
  516. Return Not String.IsNullOrWhiteSpace(SearchBox.Text)
  517. End Get
  518. End Property
  519. Public Sub SearchRun() Handles SearchBox.TextChanged
  520. ChangeAllSelected(False)
  521. If IsSearching Then
  522. '构造请求
  523. Dim QueryList As New List(Of SearchEntry(Of McMod))
  524. For Each Entry As McMod In McModLoader.Output
  525. Dim SearchSource As New List(Of KeyValuePair(Of String, Double))
  526. SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Name, 1))
  527. SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.FileName, 1))
  528. If Entry.Version IsNot Nothing Then
  529. SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Version, 0.2))
  530. End If
  531. If Entry.Description IsNot Nothing AndAlso Entry.Description <> "" Then
  532. SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Description, 0.4))
  533. End If
  534. If Entry.Comp IsNot Nothing Then
  535. If Entry.Comp.RawName <> Entry.Name Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.RawName, 1))
  536. If Entry.Comp.TranslatedName <> Entry.Comp.RawName Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.TranslatedName, 1))
  537. If Entry.Comp.Description <> Entry.Description Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.Description, 0.4))
  538. SearchSource.Add(New KeyValuePair(Of String, Double)(String.Join("", Entry.Comp.Tags), 0.2))
  539. End If
  540. QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSource})
  541. Next
  542. '进行搜索
  543. Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35)
  544. RefreshResult(SearchResult.Select(Function(r) r.Item).ToList)
  545. Else
  546. '退出搜索状态
  547. RefreshResult(McModLoader.Output)
  548. End If
  549. End Sub
  550. #End Region
  551. End Class