PageVersionMod.xaml.vb 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. Public Class PageVersionMod
  2. #Region "初始化"
  3. Private IsLoad As Boolean = False
  4. Public Sub PageOther_Loaded() Handles Me.Loaded
  5. 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 Load_Finish, 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. Private PanItems As StackPanel
  40. ''' <summary>
  41. ''' 将 Mod 列表加载为 UI。
  42. ''' </summary>
  43. Private Sub Load_Finish(Loader As LoaderTask(Of String, List(Of McMod)))
  44. Dim List As List(Of McMod) = Loader.Output
  45. Try
  46. PanList.Children.Clear()
  47. '判断应该显示哪一个页面
  48. If List.Count = 0 Then
  49. PanEmpty.Visibility = Visibility.Visible
  50. PanBack.Visibility = Visibility.Collapsed
  51. Exit Sub
  52. Else
  53. PanBack.Visibility = Visibility.Visible
  54. PanEmpty.Visibility = Visibility.Collapsed
  55. End If
  56. SearchBox.Text = ""
  57. '建立 StackPanel
  58. PanItems = New StackPanel With {.Margin = New Thickness(18, MyCard.SwapedHeight, 18, If(List.Count > 0, 20, 0)), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
  59. For Each ModEntity As McMod In List
  60. PanItems.Children.Add(McModListItem(ModEntity))
  61. Next
  62. '建立 MyCard
  63. Dim NewCard As New MyCard With {.Title = McModGetTitle(List), .Margin = New Thickness(0, 0, 0, 15)}
  64. NewCard.Children.Add(PanItems)
  65. PanList.Children.Add(NewCard)
  66. '显示提示
  67. If List.Count > 0 AndAlso Not Setup.Get("HintModDisable") Then
  68. Setup.Set("HintModDisable", True)
  69. Hint("直接点击某个 Mod 项即可将它禁用!")
  70. End If
  71. Catch ex As Exception
  72. Log(ex, "加载 Mod 列表 UI 失败", LogLevel.Feedback)
  73. End Try
  74. End Sub
  75. ''' <summary>
  76. ''' 获取 Card 的标题。
  77. ''' </summary>
  78. Private Function McModGetTitle(List As List(Of McMod)) As String
  79. Dim Counter = {0, 0, 0}
  80. For Each ModEntity As McMod In List
  81. Counter(ModEntity.State) += 1
  82. Next
  83. If List.Count = 0 Then Return "未找到任何 Mod"
  84. Dim TypeList As New List(Of String)
  85. If Counter(McMod.McModState.Fine) > 0 Then TypeList.Add("启用 " & Counter(McMod.McModState.Fine))
  86. If Counter(McMod.McModState.Disabled) > 0 Then TypeList.Add("禁用 " & Counter(McMod.McModState.Disabled))
  87. If Counter(McMod.McModState.Unavaliable) > 0 Then TypeList.Add("错误 " & Counter(McMod.McModState.Unavaliable))
  88. Return "Mod 列表(" & Join(TypeList, ",") & ")"
  89. End Function
  90. Private Function McModListItem(Entry As McMod) As MyListItem
  91. '图标
  92. Dim Logo As String
  93. Select Case Entry.State
  94. Case McMod.McModState.Fine
  95. Logo = "pack://application:,,,/images/Blocks/RedstoneLampOn.png"
  96. Case McMod.McModState.Disabled
  97. Logo = "pack://application:,,,/images/Blocks/RedstoneLampOff.png"
  98. Case Else '出错
  99. Logo = "pack://application:,,,/images/Blocks/RedstoneBlock.png"
  100. End Select
  101. '文本
  102. Dim Title As String
  103. If Entry.State = McMod.McModState.Disabled Then
  104. Title = GetFileNameWithoutExtentionFromPath(Entry.Path.Substring(0, Entry.Path.Count - ".disabled".Count)) & "(已禁用)"
  105. Else
  106. Title = GetFileNameWithoutExtentionFromPath(Entry.Path)
  107. End If
  108. Dim Desc As String
  109. If Entry.Version Is Nothing OrElse Entry.Description IsNot Nothing Then
  110. Desc = Entry.Name & If(Entry.Version Is Nothing, "", " (" & Entry.Version & ")") & " : " & If(Entry.Description, Entry.Path)
  111. ElseIf Entry.IsFileAvailable Then
  112. Desc = Entry.Path
  113. Else
  114. Desc = "存在错误 : " & Entry.Path
  115. End If
  116. 'Desc = If(Entry.ModId, "无可用名称") & " (" & If(Entry.Version, "无可用版本") & ")"
  117. 'If Entry.Dependencies.Count > 0 Then
  118. ' Dim DepList As New List(Of String)
  119. ' For Each Dep In Entry.Dependencies
  120. ' DepList.Add(Dep.Key & If(Dep.Value Is Nothing, "", "@" & Dep.Value))
  121. ' Next
  122. ' Desc += " : " & Join(DepList, ", ")
  123. 'End If
  124. '实例化
  125. AniControlEnabled += 1
  126. Dim NewItem As New MyListItem With {
  127. .LogoClickable = True, .Logo = Logo, .SnapsToDevicePixels = True, .Title = Title, .Info = Desc, .Height = 42, .Tag = Entry,
  128. .Type = MyListItem.CheckType.CheckBox, .IsScaleAnimationEnabled = False,
  129. .PaddingRight = 73,
  130. .ContentHandler = AddressOf McModContent, .Checked = SelectedMods.Contains(Entry.RawFileName)
  131. }
  132. AniControlEnabled -= 1
  133. Return NewItem
  134. End Function
  135. Private Sub McModContent(sender As MyListItem, e As EventArgs)
  136. Dim ModEntity As McMod = sender.Tag
  137. '注册点击事件
  138. AddHandler sender.Changed, AddressOf CheckChanged
  139. AddHandler sender.LogoClick, AddressOf ItemLogo_Click
  140. '图标按钮
  141. Dim BtnDel As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonDelete, .Tag = sender}
  142. BtnDel.ToolTip = "删除"
  143. ToolTipService.SetPlacement(BtnDel, Primitives.PlacementMode.Center)
  144. ToolTipService.SetVerticalOffset(BtnDel, 30)
  145. ToolTipService.SetHorizontalOffset(BtnDel, 2)
  146. AddHandler BtnDel.Click, AddressOf Delete_Click
  147. Dim BtnOpen As New MyIconButton With {.LogoScale = 1.15, .Logo = Logo.IconButtonOpen, .Tag = sender}
  148. BtnOpen.ToolTip = "打开文件位置"
  149. ToolTipService.SetPlacement(BtnOpen, Primitives.PlacementMode.Center)
  150. ToolTipService.SetVerticalOffset(BtnOpen, 30)
  151. ToolTipService.SetHorizontalOffset(BtnOpen, 2)
  152. AddHandler BtnOpen.Click, AddressOf Open_Click
  153. Dim BtnCont As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .Tag = sender}
  154. BtnCont.ToolTip = "详情"
  155. ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
  156. ToolTipService.SetVerticalOffset(BtnCont, 30)
  157. ToolTipService.SetHorizontalOffset(BtnCont, 2)
  158. AddHandler BtnCont.Click, AddressOf Info_Click
  159. AddHandler sender.MouseRightButtonDown, AddressOf Info_Click
  160. sender.Buttons = {BtnCont, BtnOpen, BtnDel}
  161. End Sub
  162. #End Region
  163. #Region "管理"
  164. ''' <summary>
  165. ''' 打开 Mods 文件夹。
  166. ''' </summary>
  167. Private Sub BtnManageOpen_Click(sender As Object, e As EventArgs) Handles BtnManageOpen.Click, BtnHintOpen.Click
  168. Try
  169. Directory.CreateDirectory(PageVersionLeft.Version.PathIndie & "mods\")
  170. OpenExplorer("""" & PageVersionLeft.Version.PathIndie & "mods\""")
  171. Catch ex As Exception
  172. Log(ex, "打开 Mods 文件夹失败", LogLevel.Msgbox)
  173. End Try
  174. End Sub
  175. #If DEBUG Then
  176. ''' <summary>
  177. ''' 检查 Mod。
  178. ''' </summary>
  179. Private Sub BtnManageCheck_Click(sender As Object, e As EventArgs) Handles BtnManageCheck.Click
  180. Try
  181. Dim Result = McModCheck(PageVersionLeft.Version, McModLoader.Output)
  182. If Result.Count > 0 Then
  183. MyMsgBox(Join(Result, vbCrLf & vbCrLf), "Mod 检查结果")
  184. Else
  185. Hint("Mod 检查完成,未发现任何问题!", HintType.Finish)
  186. End If
  187. Catch ex As Exception
  188. Log(ex, "进行 Mod 检查时出错", LogLevel.Feedback)
  189. End Try
  190. End Sub
  191. #End If
  192. ''' <summary>
  193. ''' 全选。
  194. ''' </summary>
  195. Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click
  196. ChangeAllSelected(True)
  197. End Sub
  198. #End Region
  199. #Region "选择"
  200. '选择的 Mod 的路径(不含 .disabled)
  201. Public SelectedMods As New List(Of String)
  202. '单项切换选择状态
  203. Public Sub CheckChanged(sender As MyListItem, e As RouteEventArgs)
  204. If AniControlEnabled <> 0 Then Return
  205. '更新选择了的内容
  206. Dim SelectedKey As String = CType(sender.Tag, McMod).RawFileName
  207. If sender.Checked Then
  208. If Not SelectedMods.Contains(SelectedKey) Then SelectedMods.Add(SelectedKey)
  209. Else
  210. SelectedMods.Remove(SelectedKey)
  211. End If
  212. '更新下边栏 UI
  213. RefreshBottomBar()
  214. End Sub
  215. '改变下边栏状态
  216. Private ShownCount As Integer = 0
  217. Private Sub RefreshBottomBar()
  218. '计数
  219. Dim NewCount As Integer = SelectedMods.Count
  220. Dim Selected = NewCount > 0
  221. If Selected Then LabSelect.Text = $"已选择 {NewCount} 个文件" '取消所有选择时不更新数字
  222. '按钮可用性
  223. If Selected Then
  224. Dim HasEnabled As Boolean = False
  225. Dim HasDisabled As Boolean = False
  226. For Each ModEntity In McModLoader.Output
  227. If SelectedMods.Contains(ModEntity.RawFileName) Then
  228. If ModEntity.State = McMod.McModState.Fine Then
  229. HasEnabled = True
  230. ElseIf ModEntity.State = McMod.McModState.Disabled Then
  231. HasDisabled = True
  232. End If
  233. End If
  234. Next
  235. BtnSelectDisable.IsEnabled = HasEnabled
  236. BtnSelectEnable.IsEnabled = HasDisabled
  237. End If
  238. '更新显示状态
  239. CardSelect.IsHitTestVisible = Selected
  240. If AniControlEnabled = 0 Then
  241. If Selected Then
  242. '仅在数量增加时播放出现/跳跃动画
  243. If ShownCount >= NewCount Then
  244. ShownCount = NewCount
  245. Return
  246. Else
  247. ShownCount = NewCount
  248. End If
  249. '出现/跳跃动画
  250. CardSelect.Visibility = Visibility.Visible
  251. AniStart({
  252. AaOpacity(CardSelect, 1 - CardSelect.Opacity, 60),
  253. AaTranslateY(CardSelect, -27 - TransSelect.Y, 120, Ease:=New AniEaseOutFluent(AniEasePower.Weak)),
  254. AaTranslateY(CardSelect, 3, 150, 120, Ease:=New AniEaseInoutFluent(AniEasePower.Weak)),
  255. AaTranslateY(CardSelect, -1, 90, 270, Ease:=New AniEaseInoutFluent(AniEasePower.Weak))
  256. }, "Mod Sidebar")
  257. Else
  258. '不重复播放隐藏动画
  259. If ShownCount = 0 Then Return
  260. ShownCount = 0
  261. '隐藏动画
  262. AniStart({
  263. AaOpacity(CardSelect, -CardSelect.Opacity, 90),
  264. AaTranslateY(CardSelect, -10 - TransSelect.Y, 90, Ease:=New AniEaseInFluent(AniEasePower.Weak)),
  265. AaCode(Sub() CardSelect.Visibility = Visibility.Collapsed, After:=True)
  266. }, "Mod Sidebar")
  267. End If
  268. Else
  269. AniStop("Mod Sidebar")
  270. ShownCount = NewCount
  271. If Selected Then
  272. CardSelect.Visibility = Visibility.Visible
  273. CardSelect.Opacity = 1
  274. TransSelect.Y = -25
  275. Else
  276. CardSelect.Visibility = Visibility.Collapsed
  277. CardSelect.Opacity = 0
  278. TransSelect.Y = -10
  279. End If
  280. End If
  281. End Sub
  282. '切换所有项的选择状态
  283. Private Sub ChangeAllSelected(Value As Boolean)
  284. AniControlEnabled += 1
  285. SelectedMods.Clear()
  286. If IsSearching Then
  287. '搜索中
  288. For Each Item As MyListItem In PanSearchList.Children
  289. Item.Checked = Value
  290. If Value Then SelectedMods.Add(CType(Item.Tag, McMod).RawFileName)
  291. Next
  292. If Not Value Then '只取消选择
  293. If PanItems IsNot Nothing Then
  294. For Each Item As MyListItem In PanItems.Children
  295. Item.Checked = Value
  296. Next
  297. End If
  298. End If
  299. Else
  300. '非搜索中
  301. If PanItems IsNot Nothing Then
  302. For Each Item As MyListItem In PanItems.Children
  303. Item.Checked = Value
  304. If Value Then SelectedMods.Add(CType(Item.Tag, McMod).RawFileName)
  305. Next
  306. End If
  307. End If
  308. AniControlEnabled -= 1
  309. '更新下边栏 UI
  310. RefreshBottomBar()
  311. End Sub
  312. Private Sub UnselectedAllWithAnimation() Handles Load.StateChanged, Me.PageExit
  313. Dim CacheAniControlEnabled = AniControlEnabled
  314. AniControlEnabled = 0
  315. ChangeAllSelected(False)
  316. AniControlEnabled += CacheAniControlEnabled
  317. End Sub
  318. Private Sub PageVersionMod_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
  319. If My.Computer.Keyboard.CtrlKeyDown AndAlso e.Key = Key.A Then ChangeAllSelected(True)
  320. End Sub
  321. #End Region
  322. #Region "下边栏"
  323. '启用 / 禁用
  324. Private Sub BtnSelectEorD_Click(sender As MyIconTextButton, e As RouteEventArgs) Handles BtnSelectEnable.Click, BtnSelectDisable.Click
  325. Dim IsSuccessful As Boolean = True
  326. Dim IsDisable As Boolean = sender.Equals(BtnSelectDisable)
  327. For Each ModEntity In McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)).ToList()
  328. Dim NewPath As String = Nothing
  329. If ModEntity.State = McMod.McModState.Fine And IsDisable Then
  330. '禁用
  331. NewPath = ModEntity.Path & ".disabled"
  332. ElseIf ModEntity.State = McMod.McModState.Disabled AndAlso Not IsDisable Then
  333. '启用
  334. NewPath = ModEntity.Path.Substring(0, ModEntity.Path.Count - ".disabled".Count)
  335. Else
  336. Continue For
  337. End If
  338. '重命名
  339. Try
  340. If File.Exists(NewPath) AndAlso Not File.Exists(ModEntity.Path) Then Continue For '因为未知原因 Mod 的状态已经切换完了
  341. File.Delete(NewPath)
  342. FileSystem.Rename(ModEntity.Path, NewPath)
  343. Catch ex As FileNotFoundException
  344. Log(ex, $"未找到需要重命名的 Mod({If(ModEntity.Path, "null")})", LogLevel.Feedback)
  345. RefreshList(True)
  346. Return
  347. Catch ex As Exception
  348. Log(ex, $"批量重命名 Mod 失败({If(ModEntity.Path, "null")})")
  349. IsSuccessful = False
  350. End Try
  351. '更改 Loader 和 UI 中的列表
  352. Dim NewModEntity As New McMod(NewPath)
  353. Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity)
  354. McModLoader.Output.RemoveAt(IndexOfLoader)
  355. McModLoader.Output.Insert(IndexOfLoader, NewModEntity)
  356. Dim Parent As StackPanel = If(IsSearching, PanSearchList, PanItems)
  357. Dim IndexOfUi As Integer = Parent.Children.IndexOf(Parent.Children.OfType(Of MyListItem).First(Function(i) CType(i.Tag, McMod) Is ModEntity))
  358. Parent.Children.RemoveAt(IndexOfUi)
  359. Parent.Children.Insert(IndexOfUi, McModListItem(NewModEntity))
  360. Next
  361. If Not IsSearching Then
  362. '改变禁用数量的显示
  363. CType(PanItems.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
  364. '更新加载器状态
  365. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
  366. End If
  367. If Not IsSuccessful Then
  368. Hint("由于文件被占用,部分 Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
  369. RefreshList(True)
  370. Else
  371. ChangeAllSelected(False)
  372. End If
  373. End Sub
  374. '删除
  375. Private Sub BtnSelectDelete_Click() Handles BtnSelectDelete.Click
  376. Dim IsSuccessful As Boolean = True
  377. Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
  378. Dim DeleteList As List(Of McMod) = McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)).ToList()
  379. For Each ModEntity In DeleteList
  380. '删除
  381. Try
  382. If IsShiftPressed Then
  383. File.Delete(ModEntity.Path)
  384. Else
  385. My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
  386. End If
  387. Catch ex As OperationCanceledException
  388. Log(ex, "批量删除 Mod 被主动取消")
  389. RefreshList(True)
  390. Return
  391. Catch ex As Exception
  392. Log(ex, $"批量删除 Mod 失败({ModEntity.Path})", LogLevel.Msgbox)
  393. IsSuccessful = False
  394. End Try
  395. '更改 Loader 和 UI 中的列表
  396. McModLoader.Output.Remove(ModEntity)
  397. Dim Parent As StackPanel = If(IsSearching, PanSearchList, PanItems)
  398. Dim IndexOfUi As Integer = Parent.Children.IndexOf(Parent.Children.OfType(Of MyListItem).First(Function(i) CType(i.Tag, McMod) Is ModEntity))
  399. Parent.Children.RemoveAt(IndexOfUi)
  400. Next
  401. If Not IsSearching Then
  402. '改变禁用数量的显示
  403. CType(PanItems.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
  404. '更新加载器状态
  405. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
  406. End If
  407. If Not IsSuccessful Then
  408. Hint("由于文件被占用,部分 Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
  409. RefreshList(True)
  410. ElseIf If(IsSearching, PanSearchList, PanItems).Children.Count = 0 Then
  411. RefreshList(True)
  412. Else
  413. ChangeAllSelected(False)
  414. End If
  415. If IsSuccessful Then
  416. If IsShiftPressed Then
  417. Hint($"已彻底删除 {DeleteList.Count} 个文件!", HintType.Finish)
  418. Else
  419. Hint($"已将 {DeleteList.Count} 个文件删除到回收站!", HintType.Finish)
  420. End If
  421. End If
  422. End Sub
  423. '取消选择
  424. Private Sub BtnSelectCancel_Click() Handles BtnSelectCancel.Click
  425. ChangeAllSelected(False)
  426. End Sub
  427. #End Region
  428. #Region "单个 Mod 项"
  429. '点击 Logo:切换可用状态 / 显示错误原因
  430. Public Sub ItemLogo_Click(sender As MyListItem, e As EventArgs)
  431. Try
  432. Dim ModEntity As McMod = sender.Tag
  433. Dim NewPath As String = Nothing
  434. Select Case ModEntity.State
  435. Case McMod.McModState.Fine
  436. '前置检测警告
  437. If ModEntity.IsPresetMod Then
  438. If MyMsgBox("该 Mod 可能为其他 Mod 的前置,如果禁用可能导致其他 Mod 无法使用。" & vbCrLf & "你确定要继续禁用吗?", "警告", "禁用", "取消") = 2 Then Exit Sub
  439. End If
  440. NewPath = ModEntity.Path & ".disabled"
  441. Case McMod.McModState.Disabled
  442. NewPath = ModEntity.Path.Substring(0, ModEntity.Path.Count - ".disabled".Count)
  443. Case McMod.McModState.Unavaliable
  444. MyMsgBox("无法读取此 Mod 的信息。" & vbCrLf & vbCrLf & "详细的错误信息:" & GetExceptionDetail(ModEntity.FileUnavailableReason), "Mod 读取失败")
  445. Exit Sub
  446. End Select
  447. '重命名
  448. Dim NewModEntity As New McMod(NewPath)
  449. Try
  450. File.Delete(NewPath)
  451. FileSystem.Rename(ModEntity.Path, NewPath)
  452. Catch ex As FileNotFoundException
  453. Log(ex, "未找到理应存在的 Mod 文件(" & ModEntity.Path & ")")
  454. FileSystem.Rename(NewPath, ModEntity.Path)
  455. NewModEntity = New McMod(ModEntity.Path)
  456. End Try
  457. '更改 Loader 中的列表
  458. Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity)
  459. McModLoader.Output.RemoveAt(IndexOfLoader)
  460. McModLoader.Output.Insert(IndexOfLoader, NewModEntity)
  461. '更改 UI 中的列表
  462. Dim Parent As StackPanel = sender.Parent
  463. Dim IndexOfUi As Integer = Parent.Children.IndexOf(sender)
  464. Parent.Children.RemoveAt(IndexOfUi)
  465. Parent.Children.Insert(IndexOfUi, McModListItem(NewModEntity))
  466. '仅在非搜索页面才执行,以确保搜索页内外显示一致
  467. If Not IsSearching Then
  468. '改变禁用数量的显示
  469. CType(Parent.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
  470. '更新加载器状态
  471. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
  472. End If
  473. RefreshBottomBar()
  474. Catch ex As Exception
  475. Log(ex, "单个状态改变中重命名 Mod 失败")
  476. Hint("切换 Mod 状态失败,请尝试关闭正在运行的游戏后再试!")
  477. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
  478. End Try
  479. End Sub
  480. '删除
  481. Public Sub Delete_Click(sender As MyIconButton, e As EventArgs)
  482. Try
  483. Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
  484. Dim ListItem As MyListItem = sender.Tag
  485. Dim ModEntity As McMod = ListItem.Tag
  486. '前置检测警告
  487. If ModEntity.IsPresetMod Then
  488. If MyMsgBox("该 Mod 可能为其他 Mod 的前置,如果删除可能导致其他 Mod 无法使用。" & vbCrLf & "你确定要继续删除吗?", "警告", "删除", "取消", IsWarn:=True) = 2 Then Exit Sub
  489. End If
  490. '删除
  491. If File.Exists(ModEntity.Path) Then
  492. If IsShiftPressed Then
  493. File.Delete(ModEntity.Path)
  494. Else
  495. My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
  496. End If
  497. Else
  498. '在不明原因下删除的文件可能还在列表里,如果玩家又点了一次就会出错,总之加个判断也不碍事
  499. Log("[System] 需要删除的 Mod 文件不存在(" & ModEntity.Path & ")", LogLevel.Hint)
  500. Exit Sub
  501. End If
  502. '更改 Loader 中的列表
  503. McModLoader.Output.Remove(ModEntity)
  504. '更改 UI 中的列表
  505. Dim Parent As StackPanel = ListItem.Parent
  506. Parent.Children.Remove(ListItem)
  507. If Parent.Children.Count = 0 Then
  508. RefreshList(True)
  509. Else
  510. CType(Parent.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
  511. End If
  512. '显示提示
  513. If IsShiftPressed Then
  514. Hint("已删除 " & ModEntity.FileName & "!", HintType.Finish)
  515. Else
  516. Hint("已将 " & ModEntity.FileName & " 删除到回收站!", HintType.Finish)
  517. End If
  518. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
  519. Catch ex As OperationCanceledException
  520. Log(ex, "删除 Mod 被主动取消")
  521. Catch ex As Exception
  522. Log(ex, "删除 Mod 失败", LogLevel.Feedback)
  523. End Try
  524. End Sub
  525. '详情
  526. Public Sub Info_Click(sender As Object, e As EventArgs)
  527. Try
  528. Dim ListItem As MyListItem
  529. ListItem = If(TypeOf sender Is MyIconButton, sender.Tag, sender)
  530. Dim ModEntity As McMod = ListItem.Tag
  531. '加载失败信息
  532. If ModEntity.State = McMod.McModState.Unavaliable Then
  533. MyMsgBox("无法读取此 Mod 的信息。" & vbCrLf & vbCrLf & "详细的错误信息:" & GetExceptionDetail(ModEntity.FileUnavailableReason), "Mod 读取失败")
  534. Return
  535. End If
  536. '获取信息
  537. Dim ContentLines As New List(Of String)
  538. If ModEntity.Description IsNot Nothing Then ContentLines.Add(ModEntity.Description & vbCrLf)
  539. If ModEntity.Authors IsNot Nothing Then ContentLines.Add("作者:" & ModEntity.Authors)
  540. ContentLines.Add("文件:" & ModEntity.FileName & "(" & GetString(New FileInfo(ModEntity.Path).Length) & ")")
  541. If ModEntity.Version IsNot Nothing Then ContentLines.Add("版本:" & ModEntity.Version)
  542. Dim DebugInfo As New List(Of String)
  543. If ModEntity.ModId IsNot Nothing Then
  544. DebugInfo.Add("Mod ID:" & ModEntity.ModId)
  545. End If
  546. If ModEntity.Dependencies.Count > 0 Then
  547. DebugInfo.Add("依赖于:")
  548. For Each Dep In ModEntity.Dependencies
  549. DebugInfo.Add(" - " & Dep.Key & If(Dep.Value Is Nothing, "", ",版本:" & Dep.Value))
  550. Next
  551. End If
  552. If DebugInfo.Count > 0 Then
  553. ContentLines.Add("")
  554. ContentLines.AddRange(DebugInfo)
  555. End If
  556. '获取用于搜索的 Mod 名称
  557. Dim ModOriginalName As String = ModEntity.Name.Replace(" ", "+")
  558. Dim ModSearchName As String = ModOriginalName.Substring(0, 1)
  559. For i = 1 To ModOriginalName.Count - 1
  560. Dim IsLastLower As Boolean = ModOriginalName(i - 1).ToString.ToLower.Equals(ModOriginalName(i - 1).ToString)
  561. Dim IsCurrentLower As Boolean = ModOriginalName(i).ToString.ToLower.Equals(ModOriginalName(i).ToString)
  562. If IsLastLower AndAlso Not IsCurrentLower Then
  563. '上一个字母为小写,这一个字母为大写
  564. ModSearchName += "+"
  565. End If
  566. ModSearchName += ModOriginalName(i)
  567. Next
  568. ModSearchName = ModSearchName.Replace("++", "+").Replace("pti+Fine", "ptiFine")
  569. '显示
  570. If ModEntity.Url Is Nothing Then
  571. If MyMsgBox(Join(ContentLines, vbCrLf), ModEntity.Name, "百科搜索", "返回") = 1 Then
  572. OpenWebsite("https://www.mcmod.cn/s?key=" & ModSearchName & "&site=all&filter=0")
  573. End If
  574. Else
  575. Select Case MyMsgBox(Join(ContentLines, vbCrLf), ModEntity.Name, "打开官网", "百科搜索", "返回")
  576. Case 1
  577. OpenWebsite(ModEntity.Url)
  578. Case 2
  579. OpenWebsite("https://www.mcmod.cn/s?key=" & ModSearchName & "&site=all&filter=0")
  580. End Select
  581. End If
  582. Catch ex As Exception
  583. Log(ex, "获取 Mod 详情失败", LogLevel.Feedback)
  584. End Try
  585. End Sub
  586. '打开文件所在的位置
  587. Public Sub Open_Click(sender As MyIconButton, e As EventArgs)
  588. Try
  589. Dim ListItem As MyListItem = sender.Tag
  590. Dim ModEntity As McMod = ListItem.Tag
  591. OpenExplorer("/select,""" & ModEntity.Path & """")
  592. Catch ex As Exception
  593. Log(ex, "打开 Mod 文件位置失败", LogLevel.Feedback)
  594. End Try
  595. End Sub
  596. #End Region
  597. Public ReadOnly Property IsSearching As Boolean
  598. Get
  599. Return Not String.IsNullOrWhiteSpace(SearchBox.Text)
  600. End Get
  601. End Property
  602. Public Sub SearchRun() Handles SearchBox.TextChanged
  603. ChangeAllSelected(False)
  604. If IsSearching Then
  605. '构造请求
  606. Dim QueryList As New List(Of SearchEntry(Of McMod))
  607. For Each Entry As McMod In McModLoader.Output
  608. QueryList.Add(New SearchEntry(Of McMod) With {
  609. .Item = Entry,
  610. .SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
  611. New KeyValuePair(Of String, Double)(Entry.Name, 1),
  612. New KeyValuePair(Of String, Double)(Entry.FileName, 1),
  613. New KeyValuePair(Of String, Double)(If(Entry.Description, ""), 0.5)
  614. }
  615. })
  616. Next
  617. '进行搜索,构造列表
  618. Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=5, MinBlurSimilarity:=0.35)
  619. PanSearchList.Children.Clear()
  620. If SearchResult.Count = 0 Then
  621. PanSearch.Title = "无搜索结果"
  622. PanSearchList.Visibility = Visibility.Collapsed
  623. Else
  624. PanSearch.Title = "搜索结果"
  625. For Each Result In SearchResult
  626. Dim Item = McModListItem(Result.Item)
  627. If ModeDebug Then Item.Info = If(Result.AbsoluteRight, "完全匹配,", "") & "相似度:" & Math.Round(Result.Similarity, 3) & "," & Item.Info
  628. PanSearchList.Children.Add(Item)
  629. Next
  630. PanSearchList.Visibility = Visibility.Visible
  631. End If
  632. '显示
  633. AniStart({
  634. AaOpacity(PanList, -PanList.Opacity, 100),
  635. AaCode(Sub()
  636. PanList.Visibility = Visibility.Collapsed
  637. PanSearch.Visibility = Visibility.Visible
  638. PanSearch.TriggerForceResize()
  639. End Sub,, True),
  640. AaOpacity(PanSearch, 1 - PanSearch.Opacity, 200, 60)
  641. }, "FrmVersionMod Search Switch", True)
  642. Else
  643. '隐藏
  644. LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.RunOnUpdated)
  645. AniStart({
  646. AaOpacity(PanSearch, -PanSearch.Opacity, 100),
  647. AaCode(Sub()
  648. PanSearch.Height = 0
  649. PanSearch.Visibility = Visibility.Collapsed
  650. PanList.Visibility = Visibility.Visible
  651. End Sub,, True),
  652. AaOpacity(PanList, 1 - PanList.Opacity, 150, 30)
  653. }, "FrmVersionMod Search Switch", True)
  654. End If
  655. End Sub
  656. End Class