ksaa 2025.5.16.1__py3-none-any.whl → 2025.5.23.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. kotonebot/__init__.py +0 -2
  2. kotonebot/backend/bot.py +19 -34
  3. kotonebot/backend/color.py +20 -17
  4. kotonebot/backend/context/context.py +41 -8
  5. kotonebot/backend/core.py +7 -30
  6. kotonebot/backend/dispatch.py +1 -1
  7. kotonebot/backend/image.py +26 -26
  8. kotonebot/backend/ocr.py +18 -17
  9. kotonebot/backend/preprocessor.py +0 -1
  10. kotonebot/client/__init__.py +8 -1
  11. kotonebot/client/device.py +7 -20
  12. kotonebot/client/factory.py +33 -5
  13. kotonebot/client/host/__init__.py +8 -1
  14. kotonebot/client/host/custom.py +7 -2
  15. kotonebot/client/host/leidian_host.py +200 -0
  16. kotonebot/client/host/mumu12_host.py +177 -0
  17. kotonebot/client/host/protocol.py +68 -38
  18. kotonebot/client/implements/adb.py +1 -1
  19. kotonebot/client/protocol.py +1 -1
  20. kotonebot/config/base_config.py +8 -3
  21. kotonebot/interop/win/reg.py +37 -0
  22. kotonebot/kaa/common.py +18 -2
  23. kotonebot/kaa/game_ui/badge.py +6 -6
  24. kotonebot/kaa/game_ui/common.py +6 -6
  25. kotonebot/kaa/game_ui/commu_event_buttons.py +4 -3
  26. kotonebot/kaa/game_ui/idols_overview.py +6 -6
  27. kotonebot/kaa/game_ui/schedule.py +162 -0
  28. kotonebot/kaa/game_ui/scrollable.py +7 -6
  29. kotonebot/kaa/kaa_context.py +8 -0
  30. kotonebot/kaa/main/cli.py +7 -0
  31. kotonebot/kaa/main/dmm_host.py +53 -0
  32. kotonebot/kaa/main/gr.py +508 -298
  33. kotonebot/kaa/main/kaa.py +77 -1
  34. kotonebot/kaa/metadata.py +26 -0
  35. kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  36. kotonebot/kaa/resources/game.db +0 -0
  37. kotonebot/kaa/resources/game_ver.txt +0 -0
  38. kotonebot/kaa/sprites/4503db6b-7224-4b81-9971-e7cfa56e10f2.png +0 -0
  39. kotonebot/kaa/tasks/R.py +137 -133
  40. kotonebot/kaa/tasks/daily/contest.py +123 -89
  41. kotonebot/kaa/tasks/daily/mission_reward.py +4 -4
  42. kotonebot/kaa/tasks/end_game.py +2 -9
  43. kotonebot/kaa/tasks/produce/cards.py +7 -6
  44. kotonebot/kaa/tasks/produce/common.py +16 -12
  45. kotonebot/kaa/tasks/produce/in_purodyuusu.py +5 -5
  46. kotonebot/kaa/tasks/produce/p_drink.py +4 -3
  47. kotonebot/kaa/tasks/produce/produce.py +5 -3
  48. kotonebot/kaa/tasks/start_game.py +2 -2
  49. kotonebot/primitives/__init__.py +17 -0
  50. kotonebot/primitives/geometry.py +290 -0
  51. kotonebot/primitives/visual.py +63 -0
  52. kotonebot/util.py +20 -20
  53. {ksaa-2025.5.16.1.dist-info → ksaa-2025.5.23.1.dist-info}/METADATA +1 -1
  54. {ksaa-2025.5.16.1.dist-info → ksaa-2025.5.23.1.dist-info}/RECORD +191 -183
  55. {ksaa-2025.5.16.1.dist-info → ksaa-2025.5.23.1.dist-info}/WHEEL +1 -1
  56. /kotonebot/{client/host/mumu_host.py → interop/win/__init__.py} +0 -0
  57. /kotonebot/kaa/sprites/{7971b595-44d3-4ce7-91ae-a8e5a25c543b.png → 02ff2b86-db5a-4850-ac98-4288a3f71ed8.png} +0 -0
  58. /kotonebot/kaa/sprites/{bc64dd37-48ba-45a5-af6d-457a7fb2c9fd.png → 04422a5d-2499-40fd-a08f-095ecbd051a8.png} +0 -0
  59. /kotonebot/kaa/sprites/{17da97eb-93c5-438f-8688-0be5b0756019.png → 0672e1c6-6abc-452c-82b3-af6eb7454cfa.png} +0 -0
  60. /kotonebot/kaa/sprites/{5089ea64-3f32-4520-a252-4ee278815cdd.png → 07960be4-b575-4f7f-be64-7e344dc118e0.png} +0 -0
  61. /kotonebot/kaa/sprites/{0f67c0a6-45d0-4953-b1a9-b5eb2c916173.png → 09cd4336-7d2a-4bce-9d08-8ac64a2bdcc3.png} +0 -0
  62. /kotonebot/kaa/sprites/{5ed9bef4-ab11-4186-9b21-a479eec687ce.png → 09fda5a8-c546-48f0-ae29-ebe4f4208d8b.png} +0 -0
  63. /kotonebot/kaa/sprites/{7dec3bd9-f8ee-430f-af54-0c03c4c91546.png → 0b5c2d3f-28b1-456f-a452-05ca006f8b33.png} +0 -0
  64. /kotonebot/kaa/sprites/{76b0e3b3-3438-4e88-aca8-da18c8e50ddd.png → 0c359f2a-72d4-4203-9ca3-968a1948eee8.png} +0 -0
  65. /kotonebot/kaa/sprites/{9e110778-1b66-4700-b462-64c1dea368da.png → 0ecc3e37-189c-40ad-9ee6-fb576b72a13b.png} +0 -0
  66. /kotonebot/kaa/sprites/{bbcb97e2-89b7-4de2-b480-a0442fc33b1e.png → 11c2ff97-3303-4d6d-8e4f-6da2148bbe20.png} +0 -0
  67. /kotonebot/kaa/sprites/{36d712ce-9227-4aef-86ee-4f78415b0c80.png → 128886a7-7629-4158-9538-3619542f775b.png} +0 -0
  68. /kotonebot/kaa/sprites/{ba07fa5e-3451-4520-8b10-0b240e5decec.png → 13a85dbd-e226-47cc-b6f5-c0d3b40654f5.png} +0 -0
  69. /kotonebot/kaa/sprites/{f71df091-fc71-48d4-8124-b3c46f4c4436.png → 13c8fa4a-0ae5-4ee1-a433-20f6c724466e.png} +0 -0
  70. /kotonebot/kaa/sprites/{02e69560-ec42-4453-b771-8600b5726b93.png → 18042dda-0222-4333-9d79-3afc3dc75220.png} +0 -0
  71. /kotonebot/kaa/sprites/{420e4ff4-82a3-4ea3-98a7-63efe65003a6.png → 18670c18-07e3-4378-a8fc-4f9b331db00f.png} +0 -0
  72. /kotonebot/kaa/sprites/{027dd54f-09d8-452d-8eff-66b06aecd264.png → 1959c932-1bbf-4fee-b3a1-2ecfbc6d4209.png} +0 -0
  73. /kotonebot/kaa/sprites/{b673cc06-14ef-4a22-b484-13a17b01b0d4.png → 1a8ec83b-ebba-4ff7-9737-104d3aa2ff98.png} +0 -0
  74. /kotonebot/kaa/sprites/{1e6d734e-7bc5-4f3f-a717-3931f44a7709.png → 1b6bc9ae-3f4e-4722-ae6f-d76bd65b071e.png} +0 -0
  75. /kotonebot/kaa/sprites/{0bd326fd-fad0-4e6c-957c-da08583ef231.png → 1e4671aa-2cdc-4432-9d83-c635e0a3d09d.png} +0 -0
  76. /kotonebot/kaa/sprites/{e941ae91-59bf-4a69-945b-1bcd7cf241c6.png → 2490bd58-bcf7-4c94-ab24-04e752137939.png} +0 -0
  77. /kotonebot/kaa/sprites/{f790aed5-b9f3-4c93-a14f-47629f53052d.png → 25cfb896-fed1-4361-ae64-fc45fc8a98dd.png} +0 -0
  78. /kotonebot/kaa/sprites/{6e81e54e-b69b-434a-8bbf-6e2551bddeb8.png → 2730beb1-a6c5-463d-9748-393764bc8e34.png} +0 -0
  79. /kotonebot/kaa/sprites/{3f0b91e1-898a-4f44-b116-38483bc30461.png → 2766af5c-4ad1-44e2-ab84-e8a6ac7bb172.png} +0 -0
  80. /kotonebot/kaa/sprites/{4fca090a-b94a-433a-8438-832a54ff65e8.png → 2cc68858-7af0-4a12-8c78-c4e4dcf9fff1.png} +0 -0
  81. /kotonebot/kaa/sprites/{04b4ccde-a374-4df3-b0fa-552ae1518348.png → 2e68066d-9a56-48cc-8711-1d4c080ee320.png} +0 -0
  82. /kotonebot/kaa/sprites/{4a9e612b-9e52-4eb5-a851-3e5ad68030e9.png → 32d50687-b3a2-4b34-a2f9-4418b5e14fff.png} +0 -0
  83. /kotonebot/kaa/sprites/{2179ff5c-7964-42b1-9a95-c0bd8af1b692.png → 344bedf1-fcca-4025-9ff6-cea99c91ddb4.png} +0 -0
  84. /kotonebot/kaa/sprites/{99e95c59-d5da-448d-b839-51428b2686f0.png → 346da82f-bfca-4a0f-bae4-ca9c8e4b794e.png} +0 -0
  85. /kotonebot/kaa/sprites/{be7504d5-48e5-404c-a74d-f7fa86acf276.png → 379a8811-932c-4c75-854f-943631c921d5.png} +0 -0
  86. /kotonebot/kaa/sprites/{d11d8839-90ef-433c-8555-fad5478009a0.png → 38f8f55f-e9dc-4c10-b97a-b7254d871ae9.png} +0 -0
  87. /kotonebot/kaa/sprites/{03c9182c-b5ba-4404-b6f9-50b06a86e102.png → 39b1738f-af9a-4c85-9315-2858f0b1d1ab.png} +0 -0
  88. /kotonebot/kaa/sprites/{fb529219-fc53-43e1-83ca-2313d1d33636.png → 3a58e019-6328-412a-9d2f-85a73900371e.png} +0 -0
  89. /kotonebot/kaa/sprites/{d4673e38-cf76-4062-9a71-0f31936fe49b.png → 3c2f70b5-9095-48d6-a012-4d68a6b0a975.png} +0 -0
  90. /kotonebot/kaa/sprites/{e753b92e-99bf-4d81-9673-92b5f67d129b.png → 3d016208-f8ed-45be-bfb1-ed15b231d0b8.png} +0 -0
  91. /kotonebot/kaa/sprites/{0b0e76ce-60cc-45cc-b204-227e59d39c26.png → 3e2af23e-041f-4128-8a78-cbd1297538cf.png} +0 -0
  92. /kotonebot/kaa/sprites/{edb144e1-7c82-4fcf-b426-c6294ad2112d.png → 429c30b5-7d3a-40a1-853a-ec51c8f238e7.png} +0 -0
  93. /kotonebot/kaa/sprites/{de619141-10a4-4447-89b3-6cabcbf52d8a.png → 440eeea3-b710-485e-ab40-80e2b6ce66f0.png} +0 -0
  94. /kotonebot/kaa/sprites/{1607c23d-3ab4-418b-8114-1a3bb782d246.png → 46f24175-8657-497d-97e6-1c1ee356e4cd.png} +0 -0
  95. /kotonebot/kaa/sprites/{3eb037db-4cd8-4c00-a655-fa73f612adfd.png → 4a128979-bf11-42fe-a966-a8f5ee143128.png} +0 -0
  96. /kotonebot/kaa/sprites/{7b07a31c-9e2b-4ce0-8998-ccc0592de5e0.png → 4a5ec641-38ec-46b0-83c4-d7edacb754b0.png} +0 -0
  97. /kotonebot/kaa/sprites/{e97e58cb-3412-4a8c-9a9e-dd45daa5ae02.png → 4a9c1ac7-0a61-4d40-b749-e8896322581f.png} +0 -0
  98. /kotonebot/kaa/sprites/{9fd268df-96b7-4b48-a6d1-b5da2161da8e.png → 4af7631b-3674-4491-a3fb-a514bfd6b204.png} +0 -0
  99. /kotonebot/kaa/sprites/{32a1072b-c359-4dad-80f6-c9ca558e5f99.png → 4c2c5378-d946-41c2-980e-afb8493f71ee.png} +0 -0
  100. /kotonebot/kaa/sprites/{1a668ad4-d6b0-4aed-bb99-8b1ac85659d3.png → 4c4dd8e5-5370-4381-b6d4-c260b32015cf.png} +0 -0
  101. /kotonebot/kaa/sprites/{32793e3b-613b-4b6d-bc2e-25f9993f6274.png → 4c5b8c40-3dfa-4091-95c3-257a36e9a6d3.png} +0 -0
  102. /kotonebot/kaa/sprites/{d3fa5988-1184-4478-abb9-1c9799bd4100.png → 4d0b8533-b3e2-4ea1-8204-a8d5e67e1f64.png} +0 -0
  103. /kotonebot/kaa/sprites/{0de838fb-24e9-4fe8-8e2a-cc26bce6d7d8.png → 50e462d5-ca14-4934-b35a-da3ebb8fb33f.png} +0 -0
  104. /kotonebot/kaa/sprites/{d2830bf7-e0c4-4d00-868a-6df22bdf6fcd.png → 557389eb-d0da-4c5a-a322-de3e32a81909.png} +0 -0
  105. /kotonebot/kaa/sprites/{979c7468-d9ef-4cc1-9449-2aa716caabb0.png → 57b7006a-ada9-4d9d-9655-71765251882e.png} +0 -0
  106. /kotonebot/kaa/sprites/{8f39322e-92d2-4cc6-80ef-341884b0a598.png → 59ef821b-4803-4fe3-83b8-305902f8459a.png} +0 -0
  107. /kotonebot/kaa/sprites/{a0b83694-4945-4476-aa2e-f268841ac372.png → 5af71b93-310c-48ab-b438-dba296fb9e52.png} +0 -0
  108. /kotonebot/kaa/sprites/{a03e79b3-7f44-4211-b625-2510ba8031bc.png → 5b6b5bf8-cd03-4360-9550-e15d8db6241a.png} +0 -0
  109. /kotonebot/kaa/sprites/{2fd33c51-b3a7-4ffb-9555-d25961186eee.png → 5d963589-623d-4a49-9c72-af91134720b0.png} +0 -0
  110. /kotonebot/kaa/sprites/{f4c8a757-674e-45ca-af2c-0bc409b7bca8.png → 5f01b811-9aad-4439-a70b-c099a42c36fa.png} +0 -0
  111. /kotonebot/kaa/sprites/{a1c29e77-138c-4580-a777-666815039524.png → 601d0743-7143-4c04-989b-b80fc620e678.png} +0 -0
  112. /kotonebot/kaa/sprites/{4aed7e90-76b1-4837-a6ad-e2ed2e3240ec.png → 63e71ec7-6290-4efa-89cf-69c53d805a58.png} +0 -0
  113. /kotonebot/kaa/sprites/{c15ad104-3814-467c-a211-1e54be35fc66.png → 66f5fab8-274c-4ab9-983d-ca2f8d90ea94.png} +0 -0
  114. /kotonebot/kaa/sprites/{8031a52b-afe1-4ebd-9599-1d123bc0e48b.png → 6abb63c1-025a-425e-8f33-29f83f504d75.png} +0 -0
  115. /kotonebot/kaa/sprites/{ad26884a-8371-420f-be89-7fe82ddaf1e8.png → 6d6550a6-f270-474e-b55c-b2017ef87ab2.png} +0 -0
  116. /kotonebot/kaa/sprites/{bf158b17-4d93-40f1-b9cf-4ae9226bcfc1.png → 7057e165-9ed4-485e-9609-94854ef269dd.png} +0 -0
  117. /kotonebot/kaa/sprites/{fa64ed03-4277-4ae2-a958-adb93c393457.png → 78c2c39e-6621-41d1-9a1e-7e171b001795.png} +0 -0
  118. /kotonebot/kaa/sprites/{f32e04e8-2e9a-49c2-9734-d0a02ed2d892.png → 798a9587-3f8c-424e-90af-89a08ed62ced.png} +0 -0
  119. /kotonebot/kaa/sprites/{b677c2ba-62da-4afd-8ba7-a9b40362b5bb.png → 7bbac9cd-417f-4bd5-975a-a8a25c7bd922.png} +0 -0
  120. /kotonebot/kaa/sprites/{d1a8f72b-813b-4d8a-a596-5576758d7fe2.png → 7c2f9216-56f2-4eec-8a45-1bd864316dad.png} +0 -0
  121. /kotonebot/kaa/sprites/{fe7e4f2b-b795-43b6-bf0a-4e65c9133a40.png → 7c992bae-5ded-473b-8e60-4dede8434e5d.png} +0 -0
  122. /kotonebot/kaa/sprites/{e73cacc9-08aa-4b7a-acd3-3dbe95d9f51c.png → 7e7e8772-b31a-4bbe-919e-90373a4ad5a7.png} +0 -0
  123. /kotonebot/kaa/sprites/{39151ffc-365e-45b2-a2f4-9d4c76d41524.png → 80171520-d132-4395-b2ed-e6451335b3d5.png} +0 -0
  124. /kotonebot/kaa/sprites/{04180b4a-1532-42dd-9280-0f47c1e68959.png → 82cf688e-ac85-4425-917d-10b6db9b6cc3.png} +0 -0
  125. /kotonebot/kaa/sprites/{ebcaaba7-57f8-4bcb-93da-a288a0fcc95e.png → 87292951-43c1-4039-9b92-c59c1b25b5f7.png} +0 -0
  126. /kotonebot/kaa/sprites/{4dd7db2d-3107-4fc5-8f30-cfa70bc28de1.png → 893a6bba-905e-4123-9e35-f829fd6c8b2a.png} +0 -0
  127. /kotonebot/kaa/sprites/{f9e0be54-237b-4092-8784-1a4d2eb43097.png → 8a605d31-3160-49d1-9098-45d8ee18e8d6.png} +0 -0
  128. /kotonebot/kaa/sprites/{334d4915-4600-4c81-bbb0-c52291b7d089.png → 8cb3b6c2-7fae-41cf-8f33-a0e3ea668f25.png} +0 -0
  129. /kotonebot/kaa/sprites/{6abe81b7-1a04-44e9-b390-affe47799c46.png → 8e1ca316-39e6-4b9f-b497-84ad8848a3e1.png} +0 -0
  130. /kotonebot/kaa/sprites/{f14cc536-f38c-4568-9812-d3ed95e639d3.png → 8f675963-122a-4932-9f33-07dcdcb3a51a.png} +0 -0
  131. /kotonebot/kaa/sprites/{0df088e0-737f-44ec-b39f-76239d087382.png → 907dc373-e2f5-4959-84cb-d7971a7fefd8.png} +0 -0
  132. /kotonebot/kaa/sprites/{7d5b4d44-cb46-49fb-96be-edaab5396836.png → 9359526e-c5db-4d63-adc4-08b7d704b422.png} +0 -0
  133. /kotonebot/kaa/sprites/{2860421f-2db8-4850-9f0c-0aca8bbf16d0.png → 96178cef-4868-4378-9f9c-c08780def3d6.png} +0 -0
  134. /kotonebot/kaa/sprites/{a477c873-98bd-45f0-a9a6-324e714c69cd.png → 985ec867-bc7c-47c5-8fcd-75f736f27507.png} +0 -0
  135. /kotonebot/kaa/sprites/{669f9e7c-b665-47a8-b4f5-fb2748bf88af.png → 9c98c4e6-5335-4c8b-92fa-24ec440b055e.png} +0 -0
  136. /kotonebot/kaa/sprites/{1373ec63-fd98-4be9-a925-08144f1d5ba5.png → a015cea0-d2c7-439a-b942-d4d2dad276e5.png} +0 -0
  137. /kotonebot/kaa/sprites/{6fec0efa-336f-4726-b1d9-dc83c23b297d.png → a05abc9d-9f0e-4d83-94bb-4f0b1e061035.png} +0 -0
  138. /kotonebot/kaa/sprites/{957dbdc4-8367-4a59-9bfc-d35ea11af9b8.png → a2e41d98-dd91-4e51-ba57-4f8ddfd07cfa.png} +0 -0
  139. /kotonebot/kaa/sprites/{8e78e1f1-ea2f-4779-a8cd-56336f936c81.png → a402b549-a4dd-4ff3-ad51-2aa5f8e620af.png} +0 -0
  140. /kotonebot/kaa/sprites/{ff493975-0f30-468f-a3ea-17505a2b0385.png → a5efb332-8452-49d8-ade3-882bbd445553.png} +0 -0
  141. /kotonebot/kaa/sprites/{dfe2fc89-eaf7-4027-bb53-dd17a9741e01.png → a9f47d53-fbef-4cb0-9d2d-845ef3d1f719.png} +0 -0
  142. /kotonebot/kaa/sprites/{45ae4d17-1887-4f2e-8cce-e5a4cc42e10b.png → b10596fe-22fa-4284-ab4b-1d653d4f0f07.png} +0 -0
  143. /kotonebot/kaa/sprites/{9cc7997f-3aeb-4b20-ae42-468ebfbc851e.png → b326c50f-c88c-4b99-80a7-046053423a19.png} +0 -0
  144. /kotonebot/kaa/sprites/{6d706642-441f-4bcc-b377-0fce3484be22.png → b44085c7-9777-415a-aae1-aae47c2f7321.png} +0 -0
  145. /kotonebot/kaa/sprites/{54d57991-e5d0-4346-b1f8-63e429d8a3fe.png → b629f0a7-df4f-4407-908b-a031c70e8b6f.png} +0 -0
  146. /kotonebot/kaa/sprites/{63f28640-766f-4698-b556-f0a0cbac6a1a.png → b8165178-a9ce-491a-ba57-d25c7af8533f.png} +0 -0
  147. /kotonebot/kaa/sprites/{0c3cc689-90f5-4c29-be80-04e2f2ab799a.png → b8eeacac-5679-42b9-a5b9-138598c8c6b6.png} +0 -0
  148. /kotonebot/kaa/sprites/{f89cafb7-657b-4ab4-8917-1964b242ff2e.png → b9ad5832-889a-4a5f-adc0-5dfd55126d6a.png} +0 -0
  149. /kotonebot/kaa/sprites/{16576157-f99b-4a64-b41b-3ee712c2304e.png → bcb95d32-32e1-4251-83de-ef5164d22a48.png} +0 -0
  150. /kotonebot/kaa/sprites/{7e64561b-0dab-420a-8f79-45ed6801939b.png → c0ddf15a-a6f6-42f6-86b7-e17cde60b437.png} +0 -0
  151. /kotonebot/kaa/sprites/{6d4f414d-ccd8-4a25-aa32-1b77ce0035d6.png → c24e874e-6a3e-472c-8745-edf7cac88954.png} +0 -0
  152. /kotonebot/kaa/sprites/{2b87ed7c-b01b-4ea7-ab34-ec4e37e036c0.png → c362b54d-d535-4227-8612-9bfe11fd7891.png} +0 -0
  153. /kotonebot/kaa/sprites/{1e7924dc-9dd4-4d54-add8-b394c75af1c7.png → c51132e9-f45c-40c9-8026-7d70b13dca8b.png} +0 -0
  154. /kotonebot/kaa/sprites/{5663551f-5abc-4ef8-a3fd-ba57b20cb35c.png → c60bec93-231f-498d-b3c6-0a78c9b8f37f.png} +0 -0
  155. /kotonebot/kaa/sprites/{89d6407a-982c-4dbc-8dd7-89cf79429eec.png → c64ff0a8-9f96-4ca7-902b-4f7298c1c431.png} +0 -0
  156. /kotonebot/kaa/sprites/{bda40c0d-55a9-41ad-ba8a-e8aafc52608b.png → c819d999-fef6-47bb-a94f-055d616033c7.png} +0 -0
  157. /kotonebot/kaa/sprites/{1b8b2a66-fb45-41d7-8441-04425a47bdeb.png → c85e58d3-ec5a-43ea-aa2a-04ee28e9ea21.png} +0 -0
  158. /kotonebot/kaa/sprites/{b332eb23-6653-4d17-b779-2451a3b261ab.png → c883049b-187c-4685-a63a-cff516851a95.png} +0 -0
  159. /kotonebot/kaa/sprites/{60f292d1-6c2d-4cfb-af76-568610817722.png → c8f0cc49-5df8-4d7a-9ef6-2f021c2380a5.png} +0 -0
  160. /kotonebot/kaa/sprites/{7383d7d0-8ee2-4413-b590-51cff541cab3.png → c9a8d73f-f487-45ff-aa05-a61393d27f66.png} +0 -0
  161. /kotonebot/kaa/sprites/{817c22a3-ecfe-4949-a784-59342e61a880.png → cb4c357f-b01b-4b95-b928-5affdf4ae684.png} +0 -0
  162. /kotonebot/kaa/sprites/{dff3509c-f0ec-44e2-8e0b-3c6b465d45f3.png → cc0e38b2-c2ae-4fe1-adb0-6ea73a602563.png} +0 -0
  163. /kotonebot/kaa/sprites/{c7a33e9e-2f1c-4171-b1f7-7d7dcc1a7bd3.png → cdd40676-b49d-42ad-9972-7149aa13d9bb.png} +0 -0
  164. /kotonebot/kaa/sprites/{5d912f4e-c319-4d45-85e6-de6e684a6278.png → cf76eb98-44ff-406e-913a-503a0233b4cd.png} +0 -0
  165. /kotonebot/kaa/sprites/{7b195535-7362-492f-8d87-b8eed15c6fc0.png → d21117c2-3679-4bb0-a5b3-5af5d12d8d3e.png} +0 -0
  166. /kotonebot/kaa/sprites/{7d778f82-f908-4edb-9b12-d8460589ab11.png → d37bc673-9668-4b7e-bc9d-54495129dcc0.png} +0 -0
  167. /kotonebot/kaa/sprites/{08750a02-0881-443a-9c69-c90a2ccf2a63.png → dac24ef9-e53d-4d95-aa09-fa694606c3ab.png} +0 -0
  168. /kotonebot/kaa/sprites/{31271771-5149-447c-8fae-ccc308c0a838.png → dd084696-be33-4a00-b6df-b25131b78b40.png} +0 -0
  169. /kotonebot/kaa/sprites/{a35aed53-ff78-41f0-9a19-c69fda40aeef.png → de1e3c4a-f6ed-467a-889c-25c01a613477.png} +0 -0
  170. /kotonebot/kaa/sprites/{639465a0-3c63-4307-a72c-4f9e543d2095.png → e1eb4596-73a1-471e-892b-c83cfb706bb3.png} +0 -0
  171. /kotonebot/kaa/sprites/{91940a9e-2cfc-423a-86d6-49429c051ea0.png → e1ec3ee5-e73c-44b6-b173-ab1c9382cba4.png} +0 -0
  172. /kotonebot/kaa/sprites/{096d3df5-2c95-41dd-bcc3-2e3afab47420.png → e4d076bd-7824-4496-a498-d6dc01ad90ba.png} +0 -0
  173. /kotonebot/kaa/sprites/{50a9e2a0-1166-4f1d-ad15-d8493ce0e49e.png → e551148d-1b0d-4518-8711-4161863c93ef.png} +0 -0
  174. /kotonebot/kaa/sprites/{45671af1-d731-4bb1-83f7-c9d23348308f.png → e61d855e-84d3-4a0e-b996-43fce262c2c3.png} +0 -0
  175. /kotonebot/kaa/sprites/{608217f6-b880-42ab-9be9-b4d56df87be2.png → e795f9c5-fdda-4fbc-8d38-a92512a590f4.png} +0 -0
  176. /kotonebot/kaa/sprites/{7d4d708f-c629-4f52-a0af-11aee7fcb878.png → eb446c0a-1dd2-4693-838e-98a76c02eac5.png} +0 -0
  177. /kotonebot/kaa/sprites/{35e6ad3a-8020-4619-b8ec-6506a8aa51fc.png → eb4bde42-de6e-4c62-8dc4-8885efc834a8.png} +0 -0
  178. /kotonebot/kaa/sprites/{9a5e7bc9-830f-4b01-8f94-6d4f589754c0.png → ec547e11-4952-4089-9744-1e89bd44389c.png} +0 -0
  179. /kotonebot/kaa/sprites/{40e3dac1-74fb-4501-a20f-18422d070554.png → ed4a8cff-b3df-4d7a-bfc4-8da776a8e548.png} +0 -0
  180. /kotonebot/kaa/sprites/{39d57097-6839-4030-bb51-24d6cd880897.png → efc08f1c-e78f-4df8-bff9-b45cde37f9dd.png} +0 -0
  181. /kotonebot/kaa/sprites/{9f56889b-0251-4ec1-8ccb-5cfd3bddd396.png → f02d997a-a3a8-4e18-96f1-e4176c14a5e0.png} +0 -0
  182. /kotonebot/kaa/sprites/{97bbc57d-780a-40f4-8fe1-bcaef697b601.png → f5e2e4e1-40be-481d-9293-9d47a5bce7cc.png} +0 -0
  183. /kotonebot/kaa/sprites/{bee4fbe2-365f-4145-b8f4-87c2c460cd71.png → f62dd2a2-bac6-4dc8-9a19-3e995ab80a3b.png} +0 -0
  184. /kotonebot/kaa/sprites/{666b1e8c-19fb-49e9-a761-1069f635f450.png → f64cfd95-8c87-47e6-96c3-8b7df2624ae3.png} +0 -0
  185. /kotonebot/kaa/sprites/{847cb208-a71c-42e3-97f1-18d4aa886b41.png → f8bcbc2c-9831-4e8d-9ffd-e532aa3193c3.png} +0 -0
  186. /kotonebot/kaa/sprites/{9e5c5ffc-450d-4ddc-a4ae-27c33267b056.png → fb50c7d1-b983-4e36-a998-ea17a1bdb18b.png} +0 -0
  187. /kotonebot/kaa/sprites/{f1a60528-1f35-451f-92e3-b1d5407e0f4e.png → fb97d804-42e4-45e2-8b22-01d16b5d0b6b.png} +0 -0
  188. /kotonebot/kaa/sprites/{a3140a53-ffb4-4094-a39c-240e9fe42308.png → fe337541-a6a3-4325-97b4-2bf27f51f39f.png} +0 -0
  189. /kotonebot/kaa/sprites/{1a0f2a10-c23b-47c7-aa7e-89b606f4d8ae.png → ffd3c6b7-cac2-4d45-ae37-792404ea2b40.png} +0 -0
  190. {ksaa-2025.5.16.1.dist-info → ksaa-2025.5.23.1.dist-info}/entry_points.txt +0 -0
  191. {ksaa-2025.5.16.1.dist-info → ksaa-2025.5.23.1.dist-info}/top_level.txt +0 -0
kotonebot/kaa/main/gr.py CHANGED
@@ -1,9 +1,11 @@
1
1
  import os
2
+ import traceback
2
3
  import zipfile
3
4
  import logging
4
5
  from functools import partial
6
+ from itertools import chain
5
7
  from datetime import datetime, timedelta
6
- from typing import List, Dict, Tuple, Literal, Generator
8
+ from typing import List, Dict, Tuple, Literal, Generator, Callable, Any, get_args, cast
7
9
 
8
10
  import cv2
9
11
  import gradio as gr
@@ -13,6 +15,7 @@ from kotonebot.kaa.db import IdolCard
13
15
  from kotonebot.config.manager import load_config, save_config
14
16
  from kotonebot.config.base_config import UserConfig, BackendConfig
15
17
  from kotonebot.backend.context import task_registry, ContextStackVars
18
+ from kotonebot.client.host import Mumu12Host, LeidianHost
16
19
  from kotonebot.kaa.common import (
17
20
  BaseConfig, APShopItems, CapsuleToysConfig, ClubRewardConfig, PurchaseConfig, ActivityFundsConfig,
18
21
  PresentsConfig, AssignmentConfig, ContestConfig, ProduceConfig,
@@ -21,6 +24,71 @@ from kotonebot.kaa.common import (
21
24
  )
22
25
 
23
26
  logger = logging.getLogger(__name__)
27
+ GradioInput = gr.Textbox | gr.Number | gr.Checkbox | gr.Dropdown | gr.Radio | gr.Slider | gr.Tabs | gr.Tab
28
+ ConfigKey = Literal[
29
+ # backend
30
+ 'adb_ip', 'adb_port',
31
+ 'screenshot_method', 'keep_screenshots',
32
+ 'check_emulator', 'emulator_path',
33
+ 'adb_emulator_name', 'emulator_args',
34
+ '_mumu_index', '_leidian_index',
35
+
36
+ # purchase
37
+ 'purchase_enabled',
38
+ 'money_enabled', 'ap_enabled',
39
+ 'ap_items', 'money_items',
40
+
41
+ # assignment
42
+ 'assignment_enabled',
43
+ 'mini_live_reassign', 'mini_live_duration',
44
+ 'online_live_reassign', 'online_live_duration',
45
+ 'contest_enabled',
46
+ 'select_which_contestant',
47
+
48
+ # produce
49
+ 'produce_enabled', 'produce_mode',
50
+ 'produce_count', 'produce_idols',
51
+ 'memory_sets', 'auto_set_memory',
52
+ 'auto_set_support', 'use_pt_boost',
53
+ 'use_note_boost', 'follow_producer',
54
+ 'self_study_lesson', 'prefer_lesson_ap',
55
+ 'actions_order', 'recommend_card_detection_mode',
56
+ 'use_ap_drink', 'skip_commu',
57
+ 'mission_reward_enabled',
58
+
59
+ # club reward
60
+ 'club_reward_enabled',
61
+ 'selected_note',
62
+
63
+ # upgrade support card
64
+ 'upgrade_support_card_enabled',
65
+
66
+ # capsule toys
67
+ 'capsule_toys_enabled', 'friend_capsule_toys_count',
68
+ 'sense_capsule_toys_count', 'logic_capsule_toys_count',
69
+ 'anomaly_capsule_toys_count',
70
+
71
+ # start game
72
+ 'start_game_enabled', 'start_through_kuyo',
73
+ 'game_package_name', 'kuyo_package_name',
74
+
75
+ # end game
76
+ 'exit_kaa', 'kill_game', 'kill_dmm',
77
+ 'kill_emulator', 'shutdown', 'hibernate',
78
+
79
+ 'activity_funds',
80
+ 'presents',
81
+ 'mission_reward',
82
+ 'activity_funds_enabled',
83
+ 'presents_enabled',
84
+ 'trace_recommend_card_detection',
85
+
86
+ '_selected_backend_index'
87
+
88
+ ]
89
+ CONFIG_KEY_VALUE: tuple[str] = get_args(ConfigKey)
90
+ ConfigSetFunction = Callable[[BaseConfig, Dict[ConfigKey, Any]], None]
91
+ ConfigBuilderReturnValue = Tuple[ConfigSetFunction, Dict[ConfigKey, GradioInput]]
24
92
 
25
93
  def _save_bug_report(
26
94
  version: str,
@@ -100,7 +168,7 @@ def _save_bug_report(
100
168
  final_msg = f"### 报告导出成功:{url}\n\n"
101
169
  expire_time = datetime.now() + timedelta(days=7)
102
170
  if error:
103
- final_msg += f"### 但发生了以下错误\n\n"
171
+ final_msg += "### 但发生了以下错误\n\n"
104
172
  final_msg += '\n* '.join(error.strip().split('\n'))
105
173
  final_msg += '\n'
106
174
  final_msg += f"### 此链接将于 {expire_time.strftime('%Y-%m-%d %H:%M:%S')}(7 天后)过期\n\n"
@@ -229,174 +297,22 @@ class KotoneBotUI:
229
297
  self.run_status.interrupt()
230
298
  gr.Info("任务已停止")
231
299
  return "执行任务", "任务已停止"
232
-
233
- def save_settings(
234
- self,
235
- adb_ip: str,
236
- adb_port: int,
237
- screenshot_method: Literal['adb', 'adb_raw', 'uiautomator2', 'windows'],
238
- keep_screenshots: bool,
239
- check_emulator: bool,
240
- emulator_path: str,
241
- adb_emulator_name: str,
242
- emulator_args: str,
243
- trace_recommend_card_detection: bool,
244
- purchase_enabled: bool,
245
- money_enabled: bool,
246
- ap_enabled: bool,
247
- ap_items: List[str],
248
- money_items: List[DailyMoneyShopItems],
249
- activity_funds_enabled: bool,
250
- presents_enabled: bool,
251
- assignment_enabled: bool,
252
- mini_live_reassign: bool,
253
- mini_live_duration: Literal[4, 6, 12],
254
- online_live_reassign: bool,
255
- online_live_duration: Literal[4, 6, 12],
256
- contest_enabled: bool,
257
- select_which_contestant: Literal[1, 2, 3],
258
- produce_enabled: bool,
259
- produce_mode: Literal["regular"],
260
- produce_count: int,
261
- produce_idols: List[str],
262
- memory_sets: List[str],
263
- auto_set_memory: bool,
264
- auto_set_support: bool,
265
- use_pt_boost: bool,
266
- use_note_boost: bool,
267
- follow_producer: bool,
268
- self_study_lesson: Literal['dance', 'visual', 'vocal'],
269
- prefer_lesson_ap: bool,
270
- actions_order: List[str],
271
- recommend_card_detection_mode: str,
272
- use_ap_drink: bool,
273
- skip_commu: bool,
274
- mission_reward_enabled: bool,
275
- # club reward
276
- club_reward_enabled: bool,
277
- selected_note: DailyMoneyShopItems,
278
- # upgrade support card
279
- upgrade_support_card_enabled: bool,
280
- # capsule toys
281
- capsule_toys_enabled: bool,
282
- friend_capsule_toys_count: int,
283
- sense_capsule_toys_count: int,
284
- logic_capsule_toys_count: int,
285
- anomaly_capsule_toys_count: int,
286
- # start game
287
- start_game_enabled: bool,
288
- start_through_kuyo: bool,
289
- game_package_name: str,
290
- kuyo_package_name: str,
291
- # end game
292
- exit_kaa: bool,
293
- kill_game: bool,
294
- kill_dmm: bool,
295
- kill_emulator: bool,
296
- shutdown: bool,
297
- hibernate: bool,
298
- ) -> str:
299
- ap_items_enum: List[Literal[0, 1, 2, 3]] = []
300
- ap_items_map: Dict[str, APShopItems] = {
301
- "支援强化点数提升": APShopItems.PRODUCE_PT_UP,
302
- "笔记数提升": APShopItems.PRODUCE_NOTE_UP,
303
- "重新挑战券": APShopItems.RECHALLENGE,
304
- "回忆再生成券": APShopItems.REGENERATE_MEMORY
305
- }
306
- for item in ap_items:
307
- if item in ap_items_map:
308
- ap_items_enum.append(ap_items_map[item].value) # type: ignore
309
-
310
- self.current_config.backend.adb_ip = adb_ip
311
- self.current_config.backend.adb_port = adb_port
312
- self.current_config.backend.adb_emulator_name = adb_emulator_name
313
- self.current_config.backend.screenshot_impl = screenshot_method
314
- self.current_config.keep_screenshots = keep_screenshots
315
- self.current_config.backend.check_emulator = check_emulator
316
- self.current_config.backend.emulator_path = emulator_path
317
- self.current_config.backend.emulator_args = emulator_args
318
-
319
- options = BaseConfig(
320
- purchase=PurchaseConfig(
321
- enabled=purchase_enabled,
322
- money_enabled=money_enabled,
323
- money_items=money_items,
324
- ap_enabled=ap_enabled,
325
- ap_items=ap_items_enum
326
- ),
327
- activity_funds=ActivityFundsConfig(
328
- enabled=activity_funds_enabled
329
- ),
330
- presents=PresentsConfig(
331
- enabled=presents_enabled
332
- ),
333
- assignment=AssignmentConfig(
334
- enabled=assignment_enabled,
335
- mini_live_reassign_enabled=mini_live_reassign,
336
- mini_live_duration=mini_live_duration,
337
- online_live_reassign_enabled=online_live_reassign,
338
- online_live_duration=online_live_duration
339
- ),
340
- contest=ContestConfig(
341
- enabled=contest_enabled,
342
- select_which_contestant=select_which_contestant
343
- ),
344
- produce=ProduceConfig(
345
- enabled=produce_enabled,
346
- mode=produce_mode,
347
- produce_count=produce_count,
348
- idols=produce_idols,
349
- memory_sets=[int(i) for i in memory_sets],
350
- auto_set_memory=auto_set_memory,
351
- auto_set_support_card=auto_set_support,
352
- use_pt_boost=use_pt_boost,
353
- use_note_boost=use_note_boost,
354
- follow_producer=follow_producer,
355
- self_study_lesson=self_study_lesson,
356
- prefer_lesson_ap=prefer_lesson_ap,
357
- actions_order=[ProduceAction(action) for action in actions_order],
358
- recommend_card_detection_mode=RecommendCardDetectionMode(recommend_card_detection_mode),
359
- use_ap_drink=use_ap_drink,
360
- skip_commu=skip_commu
361
- ),
362
- mission_reward=MissionRewardConfig(
363
- enabled=mission_reward_enabled
364
- ),
365
- club_reward=ClubRewardConfig(
366
- enabled=club_reward_enabled,
367
- selected_note=selected_note
368
- ),
369
- upgrade_support_card=UpgradeSupportCardConfig(
370
- enabled=upgrade_support_card_enabled
371
- ),
372
- capsule_toys=CapsuleToysConfig(
373
- enabled=capsule_toys_enabled,
374
- friend_capsule_toys_count=friend_capsule_toys_count,
375
- sense_capsule_toys_count=sense_capsule_toys_count,
376
- logic_capsule_toys_count=logic_capsule_toys_count,
377
- anomaly_capsule_toys_count=anomaly_capsule_toys_count
378
- ),
379
- start_game=StartGameConfig(
380
- enabled=start_game_enabled,
381
- start_through_kuyo=start_through_kuyo,
382
- game_package_name=game_package_name,
383
- kuyo_package_name=kuyo_package_name
384
- ),
385
- end_game=EndGameConfig(
386
- exit_kaa=exit_kaa,
387
- kill_game=kill_game,
388
- kill_dmm=kill_dmm,
389
- kill_emulator=kill_emulator,
390
- shutdown=shutdown,
391
- hibernate=hibernate
392
- ),
393
- trace=TraceConfig(
394
- recommend_card_detection=trace_recommend_card_detection
395
- )
396
- )
397
-
300
+
301
+ def save_settings2(self, return_values: list[ConfigBuilderReturnValue], *args) -> str:
302
+ options = BaseConfig()
303
+ # return_values: (set_func, { 'key': component })
304
+ keys = list(chain.from_iterable([list(data.keys()) for _, data in return_values]))
305
+ # 根据 keys *args 构建 data 字典
306
+ data = dict[ConfigKey, Any]()
307
+ assert len(keys) == len(args), "keys 与 args 长度不一致"
308
+ for key, value in zip(keys, args):
309
+ assert key in CONFIG_KEY_VALUE, f"未知的配置项:{key}"
310
+ key = cast(ConfigKey, key)
311
+ data[key] = value
312
+ # 设置结果
313
+ for (set_func, _) in return_values:
314
+ set_func(options, data)
398
315
  self.current_config.options = options
399
-
400
316
  try:
401
317
  save_config(self.config, "config.json")
402
318
  gr.Success("设置已保存,请重启程序!")
@@ -517,70 +433,183 @@ class KotoneBotUI:
517
433
  outputs=[task_result]
518
434
  )
519
435
 
520
- def _create_emulator_settings(self) -> Tuple[gr.Textbox, gr.Number, gr.Dropdown, gr.Checkbox, gr.Checkbox, gr.Textbox, gr.Textbox, gr.Textbox]:
521
- with gr.Column():
522
- gr.Markdown("### 模拟器设置")
523
- adb_ip = gr.Textbox(
524
- value=self.current_config.backend.adb_ip,
525
- label="ADB IP 地址",
526
- info=BackendConfig.model_fields['adb_ip'].description,
527
- interactive=True
528
- )
529
- adb_port = gr.Number(
530
- value=self.current_config.backend.adb_port,
531
- label="ADB 端口",
532
- info=BackendConfig.model_fields['adb_port'].description,
533
- minimum=1,
534
- maximum=65535,
535
- step=1,
536
- interactive=True
537
- )
538
- screenshot_impl = gr.Dropdown(
539
- choices=['adb', 'adb_raw', 'uiautomator2', 'windows', 'remote_windows'],
540
- value=self.current_config.backend.screenshot_impl,
541
- label="截图方法",
542
- info=BackendConfig.model_fields['screenshot_impl'].description,
543
- interactive=True
544
- )
545
- keep_screenshots = gr.Checkbox(
546
- label="保留截图数据",
547
- value=self.current_config.keep_screenshots,
548
- info=UserConfig.model_fields['keep_screenshots'].description,
549
- interactive=True
550
- )
551
- check_emulator = gr.Checkbox(
552
- label="检查并启动模拟器",
553
- value=self.current_config.backend.check_emulator,
554
- info=BackendConfig.model_fields['check_emulator'].description,
555
- interactive=True
556
- )
557
- with gr.Group(visible=self.current_config.backend.check_emulator) as check_emulator_group:
558
- emulator_path = gr.Textbox(
559
- value=self.current_config.backend.emulator_path,
560
- label="模拟器 exe 文件路径",
561
- info=BackendConfig.model_fields['emulator_path'].description,
436
+ def _create_emulator_settings(self) -> ConfigBuilderReturnValue:
437
+ gr.Markdown("### 模拟器设置")
438
+ has_mumu12 = Mumu12Host.installed()
439
+ has_leidian = LeidianHost.installed()
440
+ current_tab = 0
441
+
442
+ def _update_emulator_tab_options(impl_value: str, selected_index: int):
443
+ nonlocal current_tab
444
+ current_tab = selected_index
445
+
446
+ if selected_index == 3: # DMM
447
+ choices = ['windows', 'remote_windows']
448
+ else: # Mumu, Leidian, Custom
449
+ choices = ['adb', 'adb_raw', 'uiautomator2']
450
+
451
+ if not impl_value in choices:
452
+ new_value = choices[0]
453
+ else:
454
+ new_value = impl_value
455
+
456
+ return gr.Dropdown(choices=choices, value=new_value)
457
+
458
+ with gr.Tabs(selected=self.current_config.backend.type) as emulator_tabs:
459
+ with gr.Tab("MuMu 12", interactive=has_mumu12, id="mumu12") as tab_mumu12:
460
+ gr.Markdown("已选中 MuMu 12 模拟器")
461
+ if has_mumu12:
462
+ try:
463
+ instances = Mumu12Host.list()
464
+ mumu_instance = gr.Dropdown(
465
+ label="选择多开实例",
466
+ value=self.current_config.backend.instance_id,
467
+ choices=[(i.name, i.id) for i in instances],
468
+ interactive=True
469
+ )
470
+ except: # noqa: E722
471
+ logger.exception('Failed to list installed MuMu12')
472
+ gr.Markdown('获取 MuMu12 模拟器列表失败,请前往 QQ 群、QQ 频道或 Github 反馈 bug。')
473
+ mumu_instance = gr.Dropdown(visible=False)
474
+ else:
475
+ # 为了让 return 收集组件时不报错
476
+ mumu_instance = gr.Dropdown(visible=False)
477
+
478
+ with gr.Tab("雷电", interactive=has_leidian, id="leidian") as tab_leidian:
479
+ gr.Markdown("已选中雷电模拟器")
480
+ if has_leidian:
481
+ try:
482
+ instances = LeidianHost.list()
483
+ leidian_instance = gr.Dropdown(
484
+ label="选择多开实例",
485
+ value=self.current_config.backend.instance_id,
486
+ choices=[(i.name, i.id) for i in instances],
487
+ interactive=True
488
+ )
489
+ except: # noqa: E722
490
+ logger.exception('Failed to list installed Leidian')
491
+ gr.Markdown('获取雷电模拟器列表失败,请前往 QQ 群、QQ 频道或 Github 反馈 bug。')
492
+ leidian_instance = gr.Dropdown(visible=False)
493
+ else:
494
+ leidian_instance = gr.Dropdown(visible=False)
495
+
496
+ with gr.Tab("自定义", id="custom") as tab_custom:
497
+ gr.Markdown("已选中自定义模拟器")
498
+ adb_ip = gr.Textbox(
499
+ value=self.current_config.backend.adb_ip,
500
+ label="ADB IP 地址",
501
+ info=BackendConfig.model_fields['adb_ip'].description,
562
502
  interactive=True
563
503
  )
564
- adb_emulator_name = gr.Textbox(
565
- value=self.current_config.backend.adb_emulator_name,
566
- label="ADB 模拟器名称",
567
- info=BackendConfig.model_fields['adb_emulator_name'].description,
504
+ adb_port = gr.Number(
505
+ value=self.current_config.backend.adb_port,
506
+ label="ADB 端口",
507
+ info=BackendConfig.model_fields['adb_port'].description,
508
+ minimum=1,
509
+ maximum=65535,
510
+ step=1,
568
511
  interactive=True
569
512
  )
570
- emulator_args = gr.Textbox(
571
- value=self.current_config.backend.emulator_args,
572
- label="模拟器启动参数",
573
- info=BackendConfig.model_fields['emulator_args'].description,
513
+ check_emulator = gr.Checkbox(
514
+ label="检查并启动模拟器",
515
+ value=self.current_config.backend.check_emulator,
516
+ info=BackendConfig.model_fields['check_emulator'].description,
574
517
  interactive=True
575
518
  )
576
- check_emulator.change(
577
- fn=lambda x: gr.Group(visible=x),
578
- inputs=[check_emulator],
579
- outputs=[check_emulator_group]
580
- )
581
- return adb_ip, adb_port, screenshot_impl, keep_screenshots, check_emulator, emulator_path, adb_emulator_name, emulator_args
519
+ with gr.Group(visible=self.current_config.backend.check_emulator) as check_emulator_group:
520
+ emulator_path = gr.Textbox(
521
+ value=self.current_config.backend.emulator_path,
522
+ label="模拟器 exe 文件路径",
523
+ info=BackendConfig.model_fields['emulator_path'].description,
524
+ interactive=True
525
+ )
526
+ adb_emulator_name = gr.Textbox(
527
+ value=self.current_config.backend.adb_emulator_name,
528
+ label="ADB 模拟器名称",
529
+ info=BackendConfig.model_fields['adb_emulator_name'].description,
530
+ interactive=True
531
+ )
532
+ emulator_args = gr.Textbox(
533
+ value=self.current_config.backend.emulator_args,
534
+ label="模拟器启动参数",
535
+ info=BackendConfig.model_fields['emulator_args'].description,
536
+ interactive=True
537
+ )
538
+ check_emulator.change(
539
+ fn=lambda x: gr.Group(visible=x),
540
+ inputs=[check_emulator],
541
+ outputs=[check_emulator_group]
542
+ )
543
+
544
+ with gr.Tab("DMM", id="dmm") as tab_dmm:
545
+ gr.Markdown("已选中 DMM")
582
546
 
583
- def _create_purchase_settings(self) -> Tuple[gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Dropdown, gr.Dropdown]:
547
+ type_in_config = self.current_config.backend.type
548
+ if type_in_config in ['dmm']:
549
+ choices = ['windows', 'remote_windows']
550
+ elif type_in_config in ['mumu12', 'leidian', 'custom']:
551
+ choices = ['adb', 'adb_raw', 'uiautomator2']
552
+ else:
553
+ raise ValueError(f'Unsupported backend type: {type_in_config}')
554
+ screenshot_impl = gr.Dropdown(
555
+ choices=choices,
556
+ value=self.current_config.backend.screenshot_impl,
557
+ label="截图方法",
558
+ info=BackendConfig.model_fields['screenshot_impl'].description,
559
+ interactive=True
560
+ )
561
+
562
+ keep_screenshots = gr.Checkbox(
563
+ label="保留截图数据",
564
+ value=self.current_config.keep_screenshots,
565
+ info=UserConfig.model_fields['keep_screenshots'].description,
566
+ interactive=True
567
+ )
568
+
569
+ tab_mumu12.select(fn=partial(_update_emulator_tab_options, selected_index=0), inputs=[screenshot_impl], outputs=[screenshot_impl])
570
+ tab_leidian.select(fn=partial(_update_emulator_tab_options, selected_index=1), inputs=[screenshot_impl], outputs=[screenshot_impl])
571
+ tab_custom.select(fn=partial(_update_emulator_tab_options, selected_index=2), inputs=[screenshot_impl], outputs=[screenshot_impl])
572
+ tab_dmm.select(fn=partial(_update_emulator_tab_options, selected_index=3), inputs=[screenshot_impl], outputs=[screenshot_impl])
573
+
574
+ def set_config(_: BaseConfig, data: dict[ConfigKey, Any]) -> None:
575
+ # current_tab is updated by _update_emulator_tab_options
576
+ if current_tab == 0: # Mumu
577
+ self.current_config.backend.type = 'mumu12'
578
+ self.current_config.backend.instance_id = data['_mumu_index']
579
+ elif current_tab == 1: # Leidian
580
+ self.current_config.backend.type = 'leidian'
581
+ self.current_config.backend.instance_id = data['_leidian_index']
582
+ elif current_tab == 2: # Custom
583
+ self.current_config.backend.type = 'custom'
584
+ self.current_config.backend.instance_id = None
585
+ self.current_config.backend.adb_ip = data['adb_ip']
586
+ self.current_config.backend.adb_port = data['adb_port']
587
+ self.current_config.backend.adb_emulator_name = data['adb_emulator_name']
588
+ self.current_config.backend.check_emulator = data['check_emulator']
589
+ self.current_config.backend.emulator_path = data['emulator_path']
590
+ self.current_config.backend.emulator_args = data['emulator_args']
591
+ elif current_tab == 3: # DMM
592
+ self.current_config.backend.type = 'dmm'
593
+ self.current_config.backend.instance_id = None # DMM doesn't use instance_id here
594
+
595
+ # Common settings for all backend types
596
+ self.current_config.backend.screenshot_impl = data['screenshot_method']
597
+ self.current_config.keep_screenshots = data['keep_screenshots'] # This is a UserConfig field
598
+
599
+ return set_config, {
600
+ 'adb_ip': adb_ip,
601
+ 'adb_port': adb_port,
602
+ 'screenshot_method': screenshot_impl, # screenshot_impl is the component
603
+ 'keep_screenshots': keep_screenshots,
604
+ 'check_emulator': check_emulator,
605
+ 'emulator_path': emulator_path,
606
+ 'adb_emulator_name': adb_emulator_name,
607
+ 'emulator_args': emulator_args,
608
+ '_mumu_index': mumu_instance,
609
+ '_leidian_index': leidian_instance
610
+ }
611
+
612
+ def _create_purchase_settings(self) -> ConfigBuilderReturnValue:
584
613
  with gr.Column():
585
614
  gr.Markdown("### 商店购买设置")
586
615
  purchase_enabled = gr.Checkbox(
@@ -636,9 +665,33 @@ class KotoneBotUI:
636
665
  inputs=[purchase_enabled],
637
666
  outputs=[purchase_group]
638
667
  )
639
- return purchase_enabled, money_enabled, ap_enabled, ap_items, money_items
668
+
669
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
670
+ config.purchase.enabled = data['purchase_enabled']
671
+ config.purchase.money_enabled = data['money_enabled']
672
+ config.purchase.money_items = [DailyMoneyShopItems(x) for x in data['money_items']]
673
+ config.purchase.ap_enabled = data['ap_enabled']
674
+ ap_items_enum: List[Literal[0, 1, 2, 3]] = []
675
+ ap_items_map: Dict[str, APShopItems] = {
676
+ "支援强化点数提升": APShopItems.PRODUCE_PT_UP,
677
+ "笔记数提升": APShopItems.PRODUCE_NOTE_UP,
678
+ "重新挑战券": APShopItems.RECHALLENGE,
679
+ "回忆再生成券": APShopItems.REGENERATE_MEMORY
680
+ }
681
+ for item in data['ap_items']:
682
+ if item in ap_items_map:
683
+ ap_items_enum.append(ap_items_map[item].value) # type: ignore
684
+ config.purchase.ap_items = ap_items_enum
685
+
686
+ return set_config, {
687
+ 'purchase_enabled': purchase_enabled,
688
+ 'money_enabled': money_enabled,
689
+ 'ap_enabled': ap_enabled,
690
+ 'ap_items': ap_items,
691
+ 'money_items': money_items
692
+ }
640
693
 
641
- def _create_work_settings(self) -> Tuple[gr.Checkbox, gr.Checkbox, gr.Dropdown, gr.Checkbox, gr.Dropdown]:
694
+ def _create_work_settings(self) -> ConfigBuilderReturnValue:
642
695
  with gr.Column():
643
696
  gr.Markdown("### 工作设置")
644
697
  assignment_enabled = gr.Checkbox(
@@ -680,9 +733,24 @@ class KotoneBotUI:
680
733
  inputs=[assignment_enabled],
681
734
  outputs=[work_group]
682
735
  )
683
- return assignment_enabled, mini_live_reassign, mini_live_duration, online_live_reassign, online_live_duration
736
+ # return assignment_enabled, mini_live_reassign, mini_live_duration, online_live_reassign, online_live_duration
737
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
738
+ config.assignment.enabled = data['assignment_enabled']
739
+ config.assignment.mini_live_reassign_enabled = data['mini_live_reassign']
740
+ config.assignment.mini_live_duration = data['mini_live_duration']
741
+ config.assignment.online_live_reassign_enabled = data['online_live_reassign']
742
+ config.assignment.online_live_duration = data['online_live_duration']
743
+
744
+ return set_config, {
745
+ 'assignment_enabled': assignment_enabled,
746
+ 'mini_live_reassign': mini_live_reassign,
747
+ 'mini_live_duration': mini_live_duration,
748
+ 'online_live_reassign': online_live_reassign,
749
+ 'online_live_duration': online_live_duration
750
+ }
684
751
 
685
- def _create_contest_settings(self) -> Tuple[gr.Checkbox, gr.Dropdown]:
752
+
753
+ def _create_contest_settings(self) -> ConfigBuilderReturnValue:
686
754
  with gr.Column():
687
755
  gr.Markdown("### 竞赛设置")
688
756
  contest_enabled = gr.Checkbox(
@@ -703,9 +771,17 @@ class KotoneBotUI:
703
771
  inputs=[contest_enabled],
704
772
  outputs=[contest_group]
705
773
  )
706
- return contest_enabled, select_which_contestant
774
+
775
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
776
+ config.contest.enabled = data['contest_enabled']
777
+ config.contest.select_which_contestant = data['select_which_contestant']
778
+
779
+ return set_config, {
780
+ 'contest_enabled': contest_enabled,
781
+ 'select_which_contestant': select_which_contestant
782
+ }
707
783
 
708
- def _create_produce_settings(self):
784
+ def _create_produce_settings(self) -> ConfigBuilderReturnValue:
709
785
  with gr.Column():
710
786
  gr.Markdown("### 培育设置")
711
787
  produce_enabled = gr.Checkbox(
@@ -849,9 +925,45 @@ class KotoneBotUI:
849
925
  inputs=[auto_set_memory],
850
926
  outputs=[memory_sets_group]
851
927
  )
852
- return produce_enabled, produce_mode, produce_count, produce_idols, memory_sets, auto_set_memory, auto_set_support, use_pt_boost, use_note_boost, follow_producer, self_study_lesson, prefer_lesson_ap, actions_order, recommend_card_detection_mode, use_ap_drink, skip_commu
928
+
929
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
930
+ config.produce.enabled = data['produce_enabled']
931
+ config.produce.mode = data['produce_mode']
932
+ config.produce.produce_count = data['produce_count']
933
+ config.produce.idols = data['produce_idols']
934
+ config.produce.memory_sets = [int(i) for i in data['memory_sets']]
935
+ config.produce.auto_set_memory = data['auto_set_memory']
936
+ config.produce.auto_set_support_card = data['auto_set_support']
937
+ config.produce.use_pt_boost = data['use_pt_boost']
938
+ config.produce.use_note_boost = data['use_note_boost']
939
+ config.produce.follow_producer = data['follow_producer']
940
+ config.produce.self_study_lesson = data['self_study_lesson']
941
+ config.produce.prefer_lesson_ap = data['prefer_lesson_ap']
942
+ config.produce.actions_order = [ProduceAction(action) for action in data['actions_order']]
943
+ config.produce.recommend_card_detection_mode = RecommendCardDetectionMode(data['recommend_card_detection_mode'])
944
+ config.produce.use_ap_drink = data['use_ap_drink']
945
+ config.produce.skip_commu = data['skip_commu']
946
+
947
+ return set_config, {
948
+ 'produce_enabled': produce_enabled,
949
+ 'produce_mode': produce_mode,
950
+ 'produce_count': produce_count,
951
+ 'produce_idols': produce_idols,
952
+ 'memory_sets': memory_sets,
953
+ 'auto_set_memory': auto_set_memory,
954
+ 'auto_set_support': auto_set_support,
955
+ 'use_pt_boost': use_pt_boost,
956
+ 'use_note_boost': use_note_boost,
957
+ 'follow_producer': follow_producer,
958
+ 'self_study_lesson': self_study_lesson,
959
+ 'prefer_lesson_ap': prefer_lesson_ap,
960
+ 'actions_order': actions_order,
961
+ 'recommend_card_detection_mode': recommend_card_detection_mode,
962
+ 'use_ap_drink': use_ap_drink,
963
+ 'skip_commu': skip_commu
964
+ }
853
965
 
854
- def _create_club_reward_settings(self) -> Tuple[gr.Checkbox, gr.Dropdown]:
966
+ def _create_club_reward_settings(self) -> ConfigBuilderReturnValue:
855
967
  with gr.Column():
856
968
  gr.Markdown("### 社团奖励设置")
857
969
  club_reward_enabled = gr.Checkbox(
@@ -872,9 +984,17 @@ class KotoneBotUI:
872
984
  inputs=[club_reward_enabled],
873
985
  outputs=[club_reward_group]
874
986
  )
875
- return club_reward_enabled, selected_note
987
+
988
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
989
+ config.club_reward.enabled = data['club_reward_enabled']
990
+ config.club_reward.selected_note = DailyMoneyShopItems(data['selected_note'])
991
+
992
+ return set_config, {
993
+ 'club_reward_enabled': club_reward_enabled,
994
+ 'selected_note': selected_note
995
+ }
876
996
 
877
- def _create_capsule_toys_settings(self) -> Tuple[gr.Checkbox, gr.Number, gr.Number, gr.Number, gr.Number]:
997
+ def _create_capsule_toys_settings(self) -> ConfigBuilderReturnValue:
878
998
  with gr.Column():
879
999
  gr.Markdown("### 扭蛋设置")
880
1000
  capsule_toys_enabled = gr.Checkbox(
@@ -918,10 +1038,24 @@ class KotoneBotUI:
918
1038
  inputs=[capsule_toys_enabled],
919
1039
  outputs=[capsule_toys_group]
920
1040
  )
921
- return capsule_toys_enabled, friend_capsule_toys_count, sense_capsule_toys_count, logic_capsule_toys_count, anomaly_capsule_toys_count
1041
+
1042
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1043
+ config.capsule_toys.enabled = data['capsule_toys_enabled']
1044
+ config.capsule_toys.friend_capsule_toys_count = data['friend_capsule_toys_count']
1045
+ config.capsule_toys.sense_capsule_toys_count = data['sense_capsule_toys_count']
1046
+ config.capsule_toys.logic_capsule_toys_count = data['logic_capsule_toys_count']
1047
+ config.capsule_toys.anomaly_capsule_toys_count = data['anomaly_capsule_toys_count']
1048
+
1049
+ return set_config, {
1050
+ 'capsule_toys_enabled': capsule_toys_enabled,
1051
+ 'friend_capsule_toys_count': friend_capsule_toys_count,
1052
+ 'sense_capsule_toys_count': sense_capsule_toys_count,
1053
+ 'logic_capsule_toys_count': logic_capsule_toys_count,
1054
+ 'anomaly_capsule_toys_count': anomaly_capsule_toys_count
1055
+ }
922
1056
 
923
1057
 
924
- def _create_start_game_settings(self) -> Tuple[gr.Checkbox, gr.Checkbox, gr.Textbox, gr.Textbox]:
1058
+ def _create_start_game_settings(self) -> ConfigBuilderReturnValue:
925
1059
  with gr.Column():
926
1060
  gr.Markdown("### 启动游戏设置")
927
1061
  start_game_enabled = gr.Checkbox(
@@ -950,9 +1084,22 @@ class KotoneBotUI:
950
1084
  inputs=[start_game_enabled],
951
1085
  outputs=[start_game_group]
952
1086
  )
953
- return start_game_enabled, start_through_kuyo, game_package_name, kuyo_package_name
1087
+
1088
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1089
+ config.start_game.enabled = data['start_game_enabled']
1090
+ config.start_game.start_through_kuyo = data['start_through_kuyo']
1091
+ config.start_game.game_package_name = data['game_package_name']
1092
+ config.start_game.kuyo_package_name = data['kuyo_package_name']
1093
+
1094
+ return set_config, {
1095
+ 'start_game_enabled': start_game_enabled,
1096
+ 'start_through_kuyo': start_through_kuyo,
1097
+ 'game_package_name': game_package_name,
1098
+ 'kuyo_package_name': kuyo_package_name
1099
+ }
1100
+
954
1101
 
955
- def _create_end_game_settings(self) -> Tuple[gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox, gr.Checkbox]:
1102
+ def _create_end_game_settings(self) -> ConfigBuilderReturnValue:
956
1103
  with gr.Column():
957
1104
  gr.Markdown("### 关闭游戏设置")
958
1105
  gr.Markdown("在所有任务执行完毕后执行下面这些操作:\n(执行单个任务时不会触发)")
@@ -986,7 +1133,104 @@ class KotoneBotUI:
986
1133
  value=self.current_config.options.end_game.hibernate,
987
1134
  info=EndGameConfig.model_fields['hibernate'].description
988
1135
  )
989
- return exit_kaa, kill_game, kill_dmm, kill_emulator, shutdown, hibernate
1136
+
1137
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1138
+ config.end_game.exit_kaa = data['exit_kaa']
1139
+ config.end_game.kill_game = data['kill_game']
1140
+ config.end_game.kill_dmm = data['kill_dmm']
1141
+ config.end_game.kill_emulator = data['kill_emulator']
1142
+ config.end_game.shutdown = data['shutdown']
1143
+ config.end_game.hibernate = data['hibernate']
1144
+
1145
+ return set_config, {
1146
+ 'exit_kaa': exit_kaa,
1147
+ 'kill_game': kill_game,
1148
+ 'kill_dmm': kill_dmm,
1149
+ 'kill_emulator': kill_emulator,
1150
+ 'shutdown': shutdown,
1151
+ 'hibernate': hibernate
1152
+ }
1153
+
1154
+ def _create_activity_funds_settings(self) -> ConfigBuilderReturnValue:
1155
+ with gr.Column():
1156
+ gr.Markdown("### 活动费设置")
1157
+ activity_funds = gr.Checkbox(
1158
+ label="启用收取活动费",
1159
+ value=self.current_config.options.activity_funds.enabled,
1160
+ info=ActivityFundsConfig.model_fields['enabled'].description
1161
+ )
1162
+
1163
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1164
+ config.activity_funds.enabled = data['activity_funds']
1165
+
1166
+ return set_config, {
1167
+ 'activity_funds': activity_funds
1168
+ }
1169
+
1170
+ def _create_presents_settings(self) -> ConfigBuilderReturnValue:
1171
+ with gr.Column():
1172
+ gr.Markdown("### 礼物设置")
1173
+ presents = gr.Checkbox(
1174
+ label="启用收取礼物",
1175
+ value=self.current_config.options.presents.enabled,
1176
+ info=PresentsConfig.model_fields['enabled'].description
1177
+ )
1178
+
1179
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1180
+ config.presents.enabled = data['presents']
1181
+
1182
+ return set_config, {
1183
+ 'presents': presents
1184
+ }
1185
+
1186
+ def _create_mission_reward_settings(self) -> ConfigBuilderReturnValue:
1187
+ with gr.Column():
1188
+ gr.Markdown("### 任务奖励设置")
1189
+ mission_reward = gr.Checkbox(
1190
+ label="启用领取任务奖励",
1191
+ value=self.current_config.options.mission_reward.enabled,
1192
+ info=MissionRewardConfig.model_fields['enabled'].description
1193
+ )
1194
+
1195
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1196
+ config.mission_reward.enabled = data['mission_reward']
1197
+
1198
+ return set_config, {
1199
+ 'mission_reward': mission_reward
1200
+ }
1201
+
1202
+ def _create_upgrade_support_card_settings(self) -> ConfigBuilderReturnValue:
1203
+ with gr.Column():
1204
+ gr.Markdown("### 升级支援卡设置")
1205
+ upgrade_support_card_enabled = gr.Checkbox(
1206
+ label="启用升级支援卡",
1207
+ value=self.current_config.options.upgrade_support_card.enabled,
1208
+ info=UpgradeSupportCardConfig.model_fields['enabled'].description
1209
+ )
1210
+
1211
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1212
+ config.upgrade_support_card.enabled = data['upgrade_support_card_enabled']
1213
+
1214
+ return set_config, {
1215
+ 'upgrade_support_card_enabled': upgrade_support_card_enabled
1216
+ }
1217
+
1218
+ def _create_trace_settings(self) -> ConfigBuilderReturnValue:
1219
+ with gr.Column():
1220
+ gr.Markdown("### 跟踪设置")
1221
+ trace_recommend_card_detection = gr.Checkbox(
1222
+ label="跟踪推荐卡检测",
1223
+ value=self.current_config.options.trace.recommend_card_detection,
1224
+ info=TraceConfig.model_fields['recommend_card_detection'].description,
1225
+ interactive=True
1226
+ )
1227
+
1228
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1229
+ config.trace.recommend_card_detection = data['trace_recommend_card_detection']
1230
+
1231
+ return set_config, {
1232
+ 'trace_recommend_card_detection': trace_recommend_card_detection
1233
+ }
990
1234
 
991
1235
  def _create_settings_tab(self) -> None:
992
1236
  with gr.Tab("设置"):
@@ -999,22 +1243,10 @@ class KotoneBotUI:
999
1243
  purchase_settings = self._create_purchase_settings()
1000
1244
 
1001
1245
  # 活动费设置
1002
- with gr.Column():
1003
- gr.Markdown("### 活动费设置")
1004
- activity_funds = gr.Checkbox(
1005
- label="启用收取活动费",
1006
- value=self.current_config.options.activity_funds.enabled,
1007
- info=ActivityFundsConfig.model_fields['enabled'].description
1008
- )
1246
+ activity_funds_settings = self._create_activity_funds_settings()
1009
1247
 
1010
1248
  # 礼物设置
1011
- with gr.Column():
1012
- gr.Markdown("### 礼物设置")
1013
- presents = gr.Checkbox(
1014
- label="启用收取礼物",
1015
- value=self.current_config.options.presents.enabled,
1016
- info=PresentsConfig.model_fields['enabled'].description
1017
- )
1249
+ presents_settings = self._create_presents_settings()
1018
1250
 
1019
1251
  # 工作设置
1020
1252
  work_settings = self._create_work_settings()
@@ -1026,38 +1258,16 @@ class KotoneBotUI:
1026
1258
  produce_settings = self._create_produce_settings()
1027
1259
 
1028
1260
  # 任务奖励设置
1029
- with gr.Column():
1030
- gr.Markdown("### 任务奖励设置")
1031
- mission_reward = gr.Checkbox(
1032
- label="启用领取任务奖励",
1033
- value=self.current_config.options.mission_reward.enabled,
1034
- info=MissionRewardConfig.model_fields['enabled'].description
1035
- )
1261
+ mission_reward_settings = self._create_mission_reward_settings()
1036
1262
 
1037
1263
  # 社团奖励设置
1038
1264
  club_reward_settings = self._create_club_reward_settings()
1039
1265
 
1040
1266
  # 升级支援卡设置
1041
- with gr.Column():
1042
- gr.Markdown("### 升级支援卡设置")
1043
- upgrade_support_card_enabled = gr.Checkbox(
1044
- label="启用升级支援卡",
1045
- value=self.current_config.options.upgrade_support_card.enabled,
1046
- info=UpgradeSupportCardConfig.model_fields['enabled'].description
1047
- )
1048
-
1049
1267
  capsule_toys_settings = self._create_capsule_toys_settings()
1050
1268
 
1051
1269
  # 跟踪设置
1052
- with gr.Column():
1053
- gr.Markdown("### 跟踪设置")
1054
- gr.Markdown("跟踪功能会记录指定模块的运行情况,并保存截图。")
1055
- trace_recommend_card_detection = gr.Checkbox(
1056
- label="跟踪推荐卡检测",
1057
- value=self.current_config.options.trace.recommend_card_detection,
1058
- info=TraceConfig.model_fields['recommend_card_detection'].description,
1059
- interactive=True
1060
- )
1270
+ trace_settings = self._create_trace_settings()
1061
1271
 
1062
1272
  # 启动游戏设置
1063
1273
  start_game_settings = self._create_start_game_settings()
@@ -1069,26 +1279,26 @@ class KotoneBotUI:
1069
1279
  result = gr.Markdown()
1070
1280
 
1071
1281
  # 收集所有设置组件
1072
- all_settings = [
1073
- *emulator_settings,
1074
- trace_recommend_card_detection,
1075
- *purchase_settings,
1076
- activity_funds,
1077
- presents,
1078
- *work_settings,
1079
- *contest_settings,
1080
- *produce_settings,
1081
- mission_reward,
1082
- *club_reward_settings,
1083
- upgrade_support_card_enabled,
1084
- *capsule_toys_settings,
1085
- *start_game_settings,
1086
- *end_game_settings
1087
- ]
1088
-
1282
+ all_return_values = [
1283
+ emulator_settings,
1284
+ purchase_settings,
1285
+ activity_funds_settings,
1286
+ presents_settings,
1287
+ work_settings,
1288
+ contest_settings,
1289
+ produce_settings,
1290
+ mission_reward_settings,
1291
+ club_reward_settings,
1292
+ capsule_toys_settings,
1293
+ start_game_settings,
1294
+ end_game_settings,
1295
+ trace_settings
1296
+ ] # list of (set_func, { 'key': component, ... })
1297
+ all_components = [list(ret[1].values()) for ret in all_return_values] # [[c1, c2], [c3], ...]
1298
+ all_components = list(chain(*all_components)) # [c1, c2, c3, ...]
1089
1299
  save_btn.click(
1090
- fn=self.save_settings,
1091
- inputs=all_settings,
1300
+ fn=partial(self.save_settings2, all_return_values),
1301
+ inputs=all_components,
1092
1302
  outputs=result
1093
1303
  )
1094
1304