ksaa 2025.9b3__py3-none-any.whl → 2025.9b5__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 (174) hide show
  1. kaa/debug_entry.py +42 -0
  2. kaa/errors.py +7 -0
  3. kaa/game_ui/drinks_overview.py +14 -6
  4. kaa/main/gr.py +331 -44
  5. kaa/main/kaa.py +9 -0
  6. kaa/metadata.py +55 -0
  7. kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  8. kaa/resources/game.db +0 -0
  9. kaa/resources/game_ver.txt +0 -0
  10. kaa/resources/idol_cards/i_card-skin-amao-3-014_0.png +0 -0
  11. kaa/resources/idol_cards/i_card-skin-amao-3-014_1.png +0 -0
  12. kaa/resources/idol_cards/i_card-skin-fktn-3-016_0.png +0 -0
  13. kaa/resources/idol_cards/i_card-skin-fktn-3-016_1.png +0 -0
  14. kaa/resources/idol_cards/i_card-skin-hmsz-3-013_0.png +0 -0
  15. kaa/resources/idol_cards/i_card-skin-hmsz-3-013_1.png +0 -0
  16. kaa/resources/idol_cards/i_card-skin-hrnm-3-015_0.png +0 -0
  17. kaa/resources/idol_cards/i_card-skin-hrnm-3-015_1.png +0 -0
  18. kaa/resources/idol_cards/i_card-skin-hski-3-015_0.png +0 -0
  19. kaa/resources/idol_cards/i_card-skin-hski-3-015_1.png +0 -0
  20. kaa/resources/idol_cards/i_card-skin-hume-3-015_0.png +0 -0
  21. kaa/resources/idol_cards/i_card-skin-hume-3-015_1.png +0 -0
  22. kaa/resources/idol_cards/i_card-skin-jsna-3-014_0.png +0 -0
  23. kaa/resources/idol_cards/i_card-skin-jsna-3-014_1.png +0 -0
  24. kaa/resources/idol_cards/i_card-skin-kcna-3-015_0.png +0 -0
  25. kaa/resources/idol_cards/i_card-skin-kcna-3-015_1.png +0 -0
  26. kaa/resources/idol_cards/i_card-skin-kllj-3-014_0.png +0 -0
  27. kaa/resources/idol_cards/i_card-skin-kllj-3-014_1.png +0 -0
  28. kaa/resources/idol_cards/i_card-skin-shro-3-015_0.png +0 -0
  29. kaa/resources/idol_cards/i_card-skin-shro-3-015_1.png +0 -0
  30. kaa/resources/idol_cards/i_card-skin-ssmk-3-015_0.png +0 -0
  31. kaa/resources/idol_cards/i_card-skin-ssmk-3-015_1.png +0 -0
  32. kaa/resources/skill_cards/img_general_skillcard_ido-3_147.png +0 -0
  33. kaa/resources/skill_cards/img_general_skillcard_ido-3_149.png +0 -0
  34. kaa/sprites/7b5c8883-a1f9-4ce9-bd84-26668577dfc6.png +0 -0
  35. kaa/sprites/8fbd1aa8-d243-40b5-95e6-d9a4ecc107f2.png +0 -0
  36. kaa/tasks/R.py +134 -132
  37. kaa/tasks/daily/purchase.py +0 -2
  38. kaa/tasks/produce/cards.py +2 -2
  39. kaa/tasks/produce/produce.py +3 -0
  40. kaa/tasks/start_game.py +9 -3
  41. {ksaa-2025.9b3.dist-info → ksaa-2025.9b5.dist-info}/METADATA +8 -5
  42. {ksaa-2025.9b3.dist-info → ksaa-2025.9b5.dist-info}/RECORD +173 -147
  43. kaa/sprites/93133c4d-39e6-4ead-a6ce-3ea6303066b0.png +0 -0
  44. /kaa/sprites/{42c2b7b0-1d6f-420e-abfc-076763638275.png → 015bfe23-ce2c-460e-aa37-28b3d7560e1d.png} +0 -0
  45. /kaa/sprites/{5bf12674-852b-4d9c-b065-886b8a29b3b8.png → 01e47e1f-f724-423b-ba70-d856234c229d.png} +0 -0
  46. /kaa/sprites/{f659d1b8-f2e2-43c2-9421-7af3b2cae001.png → 05684027-1c3a-4a79-a3b8-324dc30b4c52.png} +0 -0
  47. /kaa/sprites/{783ebf90-f6d7-419b-81e2-19787425682e.png → 05caaf0f-28fd-4a05-aab1-7307bcf78747.png} +0 -0
  48. /kaa/sprites/{99276e06-774a-4ddb-b6a1-4fa827ae1997.png → 0717934b-7411-42e2-908d-f9ad5f1d233e.png} +0 -0
  49. /kaa/sprites/{2ae53e6d-f9e1-4d14-b6bf-637a36ab9fc7.png → 07d7ad36-3cf2-4c4f-905c-6eba7b97db4d.png} +0 -0
  50. /kaa/sprites/{fc044ce0-8456-401f-ace2-6c91b6e60b19.png → 110ed4b4-15ac-40ef-9852-e178b527d39f.png} +0 -0
  51. /kaa/sprites/{4f020d14-f2b0-4d6b-b6f7-4be27932517e.png → 11aaa80d-1c11-4077-a9ff-2a8ffc045117.png} +0 -0
  52. /kaa/sprites/{9e86ada7-3094-49a2-9704-86af78aaeaa8.png → 11d27619-0dd4-4681-acd6-a4bcc30f1530.png} +0 -0
  53. /kaa/sprites/{dfb9a168-a243-4752-a76c-8c52afaa9c4b.png → 1814758c-8f7f-4564-bbe2-6c7f87f9b449.png} +0 -0
  54. /kaa/sprites/{897358a6-6569-4643-8b60-77047287577d.png → 1a57efbe-f6d1-4bfb-9d58-cafc09158ba9.png} +0 -0
  55. /kaa/sprites/{a6a411ed-fbb0-4814-808d-5719cccd93bf.png → 1a73afa3-ccce-4525-b076-b0a6ad4000aa.png} +0 -0
  56. /kaa/sprites/{44f1d955-dbe5-48ff-887a-c720578a39e7.png → 1b16c4d5-7b9e-4ae2-bb0d-2990f96dfd25.png} +0 -0
  57. /kaa/sprites/{03a4f7be-8eea-4506-b8ba-19cef95612af.png → 1bc0ade2-ea41-4af4-b694-720eefeb546c.png} +0 -0
  58. /kaa/sprites/{19b610df-ac4a-463c-afdb-88a67dc7bc27.png → 1be9d3dc-9cc2-4742-83dd-cc405ee5e5e7.png} +0 -0
  59. /kaa/sprites/{5aa3920c-12ae-4678-8509-da660b4173de.png → 272eadd8-10fa-4dee-9547-a37dacce2187.png} +0 -0
  60. /kaa/sprites/{bb7cab97-c1bc-498d-af71-535769f1f4b0.png → 2c8fd695-3878-4eb9-988e-5a53e4c39bf6.png} +0 -0
  61. /kaa/sprites/{e5a018d1-1def-4511-97fd-55f6bc10a60c.png → 2e335072-f4e7-4ba5-83c8-355c43691557.png} +0 -0
  62. /kaa/sprites/{97a1cef5-7240-4456-a1c7-09a7c8edd8fd.png → 2fb54c0c-586e-4e6b-b5cd-bfb15fc73510.png} +0 -0
  63. /kaa/sprites/{67664fe3-0300-4b56-844c-1bbf0bfac3da.png → 2fd7b950-1f8f-40be-afce-ca576d512ca2.png} +0 -0
  64. /kaa/sprites/{d3a6ddfd-5bb3-47ef-a022-1024d5c3ecf2.png → 314e3b63-2a80-4a47-898f-647423257e50.png} +0 -0
  65. /kaa/sprites/{68b0d741-f1c2-4c29-bd06-85468ed4ff87.png → 31f02509-385c-4137-9a2a-87dcc0c9d858.png} +0 -0
  66. /kaa/sprites/{e7bc9fce-8b1a-4ce8-a812-0211c4d5558f.png → 35bd28b2-91f2-43d0-a744-31af6bbc588a.png} +0 -0
  67. /kaa/sprites/{4484618e-b4e4-4f8d-9c10-d32c4809c528.png → 3762c3be-3232-4f1b-8310-cef9b31f06a4.png} +0 -0
  68. /kaa/sprites/{6f499758-a73a-476f-93b5-d422dbc965c3.png → 391ea57b-172d-4d6c-a97b-46549417b2c1.png} +0 -0
  69. /kaa/sprites/{2ee4c3a8-c412-4734-ab52-88521e751f9a.png → 3996af24-d8fb-4397-98bd-cad4d6cbbd96.png} +0 -0
  70. /kaa/sprites/{9b12235d-baf7-4a76-9fd3-c9a5da9e9dc7.png → 3ba6d2cd-8583-4e90-b36e-8b2e47b3d2b6.png} +0 -0
  71. /kaa/sprites/{de80639f-e431-426b-b37d-306045f49fa9.png → 3e6c9eb8-5843-4a5c-9654-d652dcc3fb1a.png} +0 -0
  72. /kaa/sprites/{1d3b859a-f9ea-489d-82da-ec42a273b2a1.png → 402c40ed-c0bd-4475-b594-4a34c52e2300.png} +0 -0
  73. /kaa/sprites/{ce279078-fd78-4551-9aef-551bf0bcd012.png → 435b7728-f920-43b0-bc4c-83b84c4a0e84.png} +0 -0
  74. /kaa/sprites/{11ecc94a-6fd2-476e-8910-0fea18678068.png → 438080ea-284c-4556-b45c-bb1b374c6931.png} +0 -0
  75. /kaa/sprites/{512a1801-f3ff-4204-9ccb-90af00c90ff1.png → 45b0b8a2-0f5e-433a-b210-c731f8d626bb.png} +0 -0
  76. /kaa/sprites/{4ab6a7b3-fb00-42e6-8535-e2be8bc6f92b.png → 4a4d0977-3c18-4c95-a5d7-d9fb9512eddc.png} +0 -0
  77. /kaa/sprites/{f2248e03-41fb-486c-9d87-97b3acc0089a.png → 4ac65e10-4b99-4e0f-a204-b923bf16dfb1.png} +0 -0
  78. /kaa/sprites/{e8ca45b5-262b-40b7-8d2e-69e1e4d5c5a7.png → 4d95933e-a5e4-4a52-b132-7667b8ae8917.png} +0 -0
  79. /kaa/sprites/{d73318df-f20e-4a3f-b63a-af4abdc33c9f.png → 500f489c-37bd-430a-81b4-e79310d55fd8.png} +0 -0
  80. /kaa/sprites/{65291397-50c3-4b7b-8630-ab530f445bdb.png → 502cbbee-3211-4981-8090-a435933a2cd3.png} +0 -0
  81. /kaa/sprites/{1a0ee299-39f0-494f-864c-62253020b670.png → 50c87fa8-0e34-4220-9989-7f2367758058.png} +0 -0
  82. /kaa/sprites/{5a0f1984-2dad-424c-aa7d-a83c7d8c3c8d.png → 513ed0ac-22f5-4c61-a5b8-6ff55aaa1194.png} +0 -0
  83. /kaa/sprites/{b4576ed5-6e78-430d-b977-82f9030b70bd.png → 521317ee-26f2-419a-af95-b1e22cb7c923.png} +0 -0
  84. /kaa/sprites/{99023408-1bb5-43ad-8c70-3a10761d9956.png → 53104f5d-1cd3-486c-a4f0-00fc3bc62d2b.png} +0 -0
  85. /kaa/sprites/{dcc75592-c284-4e22-a229-600c1b30aa68.png → 56a0a713-bcb3-459e-bc8c-2da22c114107.png} +0 -0
  86. /kaa/sprites/{b74a9b0a-daad-4d2e-920e-5a6f2b15e67e.png → 573e5961-218c-46ba-95e9-321b5093ae25.png} +0 -0
  87. /kaa/sprites/{21c9b731-8bfd-47a7-8933-175dc47e642f.png → 59888d84-409f-479d-a338-9b7649f8b7e3.png} +0 -0
  88. /kaa/sprites/{e4084dd2-3db9-4a16-893b-d18bb0b60b26.png → 5a4f4fed-744a-475a-a251-dac04cf31084.png} +0 -0
  89. /kaa/sprites/{f9135063-fa0d-4ff0-8b37-d4c09dc28f18.png → 5a6c9933-e29f-41e0-9d16-36caca895c8e.png} +0 -0
  90. /kaa/sprites/{d60da1fc-f6cb-4d60-8eee-cb51284b6051.png → 5aa8d676-9900-4060-ae1b-f93f0f6c0e92.png} +0 -0
  91. /kaa/sprites/{c614fecb-c6b6-492c-8c58-9e8ba05f43cb.png → 5b213adc-07a8-4b61-8625-d80d255115a7.png} +0 -0
  92. /kaa/sprites/{273b2d25-da0f-41f5-995c-b8d5533008fe.png → 5d34161f-d768-4a72-8892-9c33e60ed32c.png} +0 -0
  93. /kaa/sprites/{b1b0f042-0e4b-42c9-ab6f-b5e9ab3afcaf.png → 609e6429-1652-4a32-a55b-52de362ed8b6.png} +0 -0
  94. /kaa/sprites/{08d4f0d1-43d5-44f8-814f-eba273f96903.png → 6809c6c0-bf4c-454b-90e9-9714e466d9de.png} +0 -0
  95. /kaa/sprites/{518b81e0-0ba6-4b63-a73f-07dccb3b5cc6.png → 681e68bb-9c31-4ddc-bc92-f25f5cd1d230.png} +0 -0
  96. /kaa/sprites/{f9baa6dd-506a-4c2b-a3b7-a4dbff4f53ae.png → 693cfb2b-c167-434e-bd24-ec48c2aa5aba.png} +0 -0
  97. /kaa/sprites/{ea9ff1a6-f8ae-4af3-bf12-5078fc51d87f.png → 69ea86ad-6624-4d6d-bfad-5a48d5a716a8.png} +0 -0
  98. /kaa/sprites/{ec613742-5f1f-4001-82d3-26f8c3e25314.png → 6b9092c3-712f-44dd-9b07-ba6d6e8f7190.png} +0 -0
  99. /kaa/sprites/{c1788160-27ba-4faa-9fb3-3d07e07bad82.png → 6c7e7ae3-7565-46ee-88bc-1be28fdafebb.png} +0 -0
  100. /kaa/sprites/{4e83a559-b52d-4369-8def-e2af428a8638.png → 6e5aad88-8c39-4b23-9809-103f16ea2033.png} +0 -0
  101. /kaa/sprites/{6fd65854-70c0-4ef7-ad6d-5f576c2ce0d2.png → 758b4d93-3594-452b-82db-c1e214916595.png} +0 -0
  102. /kaa/sprites/{56e88b0b-d73e-4304-ab7d-6865feb66dd3.png → 76962167-9afb-4518-948c-5436c8d23be5.png} +0 -0
  103. /kaa/sprites/{ab8a2dfe-01e8-408b-896a-b948823bbc03.png → 78348d18-4abe-40af-b7a2-d1a7b3a2990a.png} +0 -0
  104. /kaa/sprites/{ac9e9295-1063-4c39-aa8a-4b033c89dd3c.png → 79945bc4-fed5-49c3-b09d-84044d6f2e01.png} +0 -0
  105. /kaa/sprites/{d8e422b6-830e-47a7-a2db-b63e17a21d51.png → 7acefede-7dda-4cd0-80a9-ebcdc02835b4.png} +0 -0
  106. /kaa/sprites/{6d6b7b99-ad18-4e5d-bdc3-dac225752eb7.png → 7d14a6f1-51d3-43d3-b6d8-ce40f7f07870.png} +0 -0
  107. /kaa/sprites/{3ae23a66-efd4-4c21-83f7-aa0b2f045a50.png → 7fbf97e9-2045-4fed-8ca3-8a35964deb28.png} +0 -0
  108. /kaa/sprites/{69412d23-7c85-4717-a0c6-1f7826d9cbb2.png → 80297f84-00ec-40f4-b9ac-4a49d9bfaf27.png} +0 -0
  109. /kaa/sprites/{372bf1ba-8a61-4893-9ec1-336826d78464.png → 8346fa88-c20a-4c17-8c74-3bf2385749e8.png} +0 -0
  110. /kaa/sprites/{5d8f949c-e68d-44e6-a798-43b3f7f76db6.png → 838154d8-9062-433b-9f10-13827a01f615.png} +0 -0
  111. /kaa/sprites/{8780a0c9-d947-4ce3-924a-59d378b2d08a.png → 88647fc6-e670-478f-808b-0afc9905cf02.png} +0 -0
  112. /kaa/sprites/{c2cf69b5-f4e5-4f7f-a406-880ff11e5f4d.png → 889783ec-222d-4cf3-989a-edd19d5932f8.png} +0 -0
  113. /kaa/sprites/{7373803b-3557-4c6b-9b9b-fdb191af3286.png → 88ef007e-18f1-4d38-ac89-e70202957f6e.png} +0 -0
  114. /kaa/sprites/{291c1c6e-9e3c-440d-98f9-dfe2c27ce751.png → 8a0b3148-a21a-45d8-b95f-11d0fd87f442.png} +0 -0
  115. /kaa/sprites/{662dadc7-04d2-48be-824e-c7b1d3719676.png → 8a5864a5-6438-48d3-b11a-77f6841e38b8.png} +0 -0
  116. /kaa/sprites/{037ce002-5d67-412f-928a-5fcc3cd3df0f.png → 8aac14d1-cba9-4fd5-9082-a82e1459faf8.png} +0 -0
  117. /kaa/sprites/{b9f51636-7f8e-4297-991f-b686d105c97b.png → 8ec60800-ca3a-4744-b09a-c121ac03ad75.png} +0 -0
  118. /kaa/sprites/{8357bf4e-80aa-4a33-a874-3d7c1b47d452.png → 8f1ae6f0-4de7-4b4f-90ad-a623faa06318.png} +0 -0
  119. /kaa/sprites/{2f39035d-7e56-43ce-ade1-000ac6632cd7.png → 8f53d345-c3b3-48cd-8c8a-0f6d0935ceec.png} +0 -0
  120. /kaa/sprites/{4d6d0a7e-d006-4233-b4de-9024c4b08ce8.png → 91f9bfff-f5ff-469c-bbac-e665ebcb2e40.png} +0 -0
  121. /kaa/sprites/{42d5c5fb-2600-41e5-9480-2796b6d631d6.png → 920a4801-060b-43e5-9700-f360cdda4f18.png} +0 -0
  122. /kaa/sprites/{7ed170b5-d1ec-47ed-b4e1-000c7da241a3.png → 93aaddcc-67c6-4d11-adef-26f29a51e69d.png} +0 -0
  123. /kaa/sprites/{75684858-63a9-4b26-a175-67c6648d9bbe.png → 9858dcde-51bb-4357-841e-86c2234c051c.png} +0 -0
  124. /kaa/sprites/{1b675788-acb2-46c0-9ffc-c50ed770ae37.png → 99532e97-930f-45e1-aea1-2aaedeebe51a.png} +0 -0
  125. /kaa/sprites/{a1fec50c-8fcc-4fe2-8968-9253489d90db.png → 9b5e5a82-2718-481d-a74c-13cc5c4ba03e.png} +0 -0
  126. /kaa/sprites/{031cd28e-a1e6-469f-b6af-c68cc4b2dc2e.png → 9c9540c9-3c57-4eba-b97b-6ccc6c07bc4d.png} +0 -0
  127. /kaa/sprites/{a92a8ca8-b166-45c7-9508-d9e2955305ee.png → 9e284692-4817-437c-9d87-7208e5caf777.png} +0 -0
  128. /kaa/sprites/{4a43008e-f6ff-4302-99f6-77b9e082e64d.png → a03fec79-53b7-462d-a383-3496790e1285.png} +0 -0
  129. /kaa/sprites/{4c99205c-6787-463f-ae4d-bb1951c79686.png → a0e0fb8d-d196-45dc-b395-6c63ce4a10c4.png} +0 -0
  130. /kaa/sprites/{ca42efda-8bd8-416e-9f0c-d54c6af990bf.png → a1481be8-dd35-45aa-a5a0-2d3afe6fc2e4.png} +0 -0
  131. /kaa/sprites/{46049707-af5d-4dcd-9620-6a20eb8748e7.png → a15ea6da-7692-47cc-b808-d08c06eee4ef.png} +0 -0
  132. /kaa/sprites/{d0befb58-59f3-4956-af23-bacd9395f161.png → a612a68c-0c84-4528-8396-3e03e2c93844.png} +0 -0
  133. /kaa/sprites/{608f1b36-9c20-4c25-9881-7ef3579cabaa.png → aaff6d7b-047f-49a3-9e1a-b238d17d6bca.png} +0 -0
  134. /kaa/sprites/{89b14f97-894e-45b2-968c-97f28b833c73.png → ab21e45a-60b2-4097-9c56-559f1e7116b2.png} +0 -0
  135. /kaa/sprites/{f42771a1-460b-4636-b8e1-e38472bdda8b.png → ac5d3547-1687-4a8b-b61e-b668fc1119c1.png} +0 -0
  136. /kaa/sprites/{5fa8ba1e-5c58-4a39-b389-4c0d3d60c313.png → afe5014f-11d6-4b05-8e26-55ed94a29133.png} +0 -0
  137. /kaa/sprites/{ef5fdf85-d2cc-42e6-bd14-c29042bcf72c.png → b1119377-955b-4f24-9c9d-1df1eead0038.png} +0 -0
  138. /kaa/sprites/{d2eb65a1-738c-4e3b-bc61-78ec078632fe.png → b20036cf-4106-49b6-ab48-c85590b255fd.png} +0 -0
  139. /kaa/sprites/{dd9108fb-d251-4cc1-a0e7-3dae7362b7f6.png → b523b4b7-07a5-4d10-bb9f-fffa592a2598.png} +0 -0
  140. /kaa/sprites/{bb384d8c-4b92-402a-a89e-ec5e1b9203ea.png → b88c6cc4-e416-4e00-a8c2-15af0e2c1dba.png} +0 -0
  141. /kaa/sprites/{4c84d3da-5086-43a1-b820-53c19a90c533.png → bacba5c4-ec4a-4eb5-96c7-423059879668.png} +0 -0
  142. /kaa/sprites/{97b1f9c2-3899-49a7-b23d-8e422beaf0ca.png → bc8f690f-1db3-44d6-a1bf-ebd23418a822.png} +0 -0
  143. /kaa/sprites/{3fba6323-e557-4920-9548-f26b75a351c5.png → bff5a450-6790-4462-be0b-d6a1beff68e0.png} +0 -0
  144. /kaa/sprites/{830691ea-cf58-4429-ab54-32414583a4ee.png → c0e89ee7-0815-4e60-8c7b-972d093f1d0d.png} +0 -0
  145. /kaa/sprites/{33e3097a-50ed-4b1f-a806-f765eefba6e8.png → c22b8b54-4ddc-41fe-ad53-62a89d8d350e.png} +0 -0
  146. /kaa/sprites/{a9fbfe75-ee6f-46a4-81a5-81bf465d4bb0.png → c3fbd35f-3c70-4dad-9302-67e817b69052.png} +0 -0
  147. /kaa/sprites/{579de834-fb1d-4cb9-801c-6885de92a290.png → c6f7ef85-2514-4aa6-ac5f-49d579418606.png} +0 -0
  148. /kaa/sprites/{d605f177-46dc-43e2-9e3f-dc5ceb4bd729.png → caa21e62-1bca-4ed1-9db3-8cba2e640b13.png} +0 -0
  149. /kaa/sprites/{c7ed0a32-b15d-4fdd-a0a4-4be756619c78.png → cbe6dd1f-ca7f-4a5e-842a-2d8d8e4ccb2b.png} +0 -0
  150. /kaa/sprites/{f7051f86-9e8a-4a01-8e3e-23f8c092aa0d.png → cf28583c-09c0-43ef-b4d0-9c6fdd7f65cd.png} +0 -0
  151. /kaa/sprites/{b1ac9ebe-d393-4c8a-9282-e1334f2835f6.png → d09a11b5-78bb-4512-8a38-4adbfd61e84f.png} +0 -0
  152. /kaa/sprites/{bb3b7c29-f31e-42c1-8f1a-6ec95e766592.png → d1cdd520-854d-476c-818e-10990169f374.png} +0 -0
  153. /kaa/sprites/{484ba2a3-3a4b-42c1-bde1-8f0631017e73.png → d238c9ff-51d4-4328-a85e-75c36b3c2066.png} +0 -0
  154. /kaa/sprites/{9b5a6710-1a7b-44b0-ad36-7f1d1b62c014.png → d3dcd6fc-cfb8-4f05-ae55-99d88982f93d.png} +0 -0
  155. /kaa/sprites/{05eeb26a-2ecb-4804-ae68-85221fcdbe00.png → d8eafb6b-28ee-4be9-963b-da9831271df8.png} +0 -0
  156. /kaa/sprites/{5011f0a8-bb49-44ec-be4e-afbf7c4d5431.png → da474a58-eafb-4ada-af5c-d505f972c59e.png} +0 -0
  157. /kaa/sprites/{3f838a2c-a020-4a3e-a9c0-551132d057a2.png → db28a5b0-fc58-49cb-96bf-f991a9a0a288.png} +0 -0
  158. /kaa/sprites/{59c4ab1b-494e-4ac1-b21a-c6364bf7ae8a.png → ded9a710-6fe0-43a2-a56c-48fec91e386c.png} +0 -0
  159. /kaa/sprites/{92ed005c-291c-425e-ab0f-455be98ef149.png → e6e6494b-eb22-4651-b67c-be67afe3ff37.png} +0 -0
  160. /kaa/sprites/{1f96ddc2-c429-4806-9bc1-802136d37a6f.png → e89d6cb9-4ca7-4c8a-a77a-843fec97d710.png} +0 -0
  161. /kaa/sprites/{ee9ad821-991c-43d2-8947-f46016e2f534.png → e8e118e3-53a3-40c1-a852-1789089578b2.png} +0 -0
  162. /kaa/sprites/{42e2b5df-19dd-493d-8739-4c2ad596331b.png → ea9616c5-dd56-4619-a362-75f5730a1f9d.png} +0 -0
  163. /kaa/sprites/{e62a2b06-9aa5-43a3-8c5b-9de75957ad59.png → ebbc9a2b-70fc-48df-8e4e-0b107fc9aeb2.png} +0 -0
  164. /kaa/sprites/{febc5122-b2d3-4e63-a054-28de0e3eba05.png → edfc3ed9-fecc-413e-bbb4-8bcfd8e106cd.png} +0 -0
  165. /kaa/sprites/{cfd5b23c-f823-4551-8986-385a6d08ac4f.png → efca65f0-62e9-4006-91ed-06583170cba8.png} +0 -0
  166. /kaa/sprites/{3823cd03-e50a-45ee-bd9f-627d5d41ae82.png → f0638571-d6e1-49bb-a201-039c2846f884.png} +0 -0
  167. /kaa/sprites/{336cd0be-5f48-4286-b6e4-820ef8ba55dd.png → f07608fd-90f2-401f-a3ca-ac2c07d25da2.png} +0 -0
  168. /kaa/sprites/{6dffeb89-24ff-4d56-a059-367cd0a16a48.png → f15a6f61-7a41-455f-96b8-ee20c50bc0c7.png} +0 -0
  169. /kaa/sprites/{9a34ecf2-75f6-4fc6-9214-e27bb7be4b89.png → fb93db81-7804-4175-a758-4da50bbfb24b.png} +0 -0
  170. /kaa/sprites/{f8e38b5e-6820-423c-937c-27aff9cd528c.png → ff2106af-052c-4976-904b-749c4f1b5d3e.png} +0 -0
  171. {ksaa-2025.9b3.dist-info → ksaa-2025.9b5.dist-info}/WHEEL +0 -0
  172. {ksaa-2025.9b3.dist-info → ksaa-2025.9b5.dist-info}/entry_points.txt +0 -0
  173. {ksaa-2025.9b3.dist-info → ksaa-2025.9b5.dist-info}/licenses/LICENSE +0 -0
  174. {ksaa-2025.9b3.dist-info → ksaa-2025.9b5.dist-info}/top_level.txt +0 -0
kaa/debug_entry.py ADDED
@@ -0,0 +1,42 @@
1
+ import sys
2
+ import runpy
3
+ import logging
4
+ import argparse
5
+
6
+ from kaa.common import BaseConfig
7
+
8
+
9
+ def run_script(script_path: str) -> None:
10
+ """
11
+ 使用 runpy 运行指定的 Python 脚本
12
+
13
+ Args:
14
+ script_path: Python 脚本的路径
15
+ """
16
+ logging.basicConfig(level=logging.INFO, format='[%(asctime)s] [%(levelname)s] [%(name)s] [%(funcName)s] [%(lineno)d] %(message)s')
17
+ # 获取模块名
18
+ module_name = script_path.strip('.py').lstrip('projects/').replace('\\', '/').strip('/').replace('/', '.')
19
+
20
+ print(f"正在运行脚本: {script_path}")
21
+ # 运行脚本
22
+ from kotonebot.backend.context import init_context, manual_context
23
+ from kaa.main.kaa import Kaa
24
+ logging.getLogger('kotonebot').setLevel(logging.DEBUG)
25
+ logging.getLogger('kaa').setLevel(logging.DEBUG)
26
+ config_path = './config.json'
27
+ kaa_instance = Kaa(config_path)
28
+ init_context(config_type=BaseConfig, target_device=kaa_instance._on_create_device())
29
+ kaa_instance._on_after_init_context()
30
+ manual_context().begin()
31
+ runpy.run_module(module_name, run_name="__main__")
32
+
33
+ def main():
34
+ parser = argparse.ArgumentParser(description='运行指定的 Python 脚本')
35
+ parser.add_argument('script_path', help='要运行的 Python 脚本路径')
36
+
37
+ args = parser.parse_args()
38
+ run_script(args.script_path)
39
+
40
+
41
+ if __name__ == '__main__':
42
+ main()
kaa/errors.py CHANGED
@@ -56,4 +56,11 @@ class ElevationRequiredError(KaaUserFriendlyError):
56
56
  super().__init__(
57
57
  '请以管理员身份运行 kaa。',
58
58
  'https://www.kdocs.cn/l/cetCY8mGKHLj?linkname=qOqulS4KeX'
59
+ )
60
+
61
+ class GameUpdateNeededError(KaaUserFriendlyError):
62
+ def __init__(self):
63
+ super().__init__(
64
+ '游戏本体需要更新。kaa 暂不支持自动更新,请前往 Play Store 手动更新游戏。',
65
+ 'https://www.baidu.com/s?wd=%E5%BF%AB%E5%8E%BB%E6%9B%B4%E6%96%B0%E6%B8%B8%E6%88%8F%E5%95%8A%EF%BC%8C%E8%BF%98%E7%82%B9%E4%BB%80%E4%B9%88%E6%89%93%E5%BC%80%E5%B8%AE%E5%8A%A9'
59
66
  )
@@ -21,7 +21,9 @@ def preprocess_drink_slot_img(img: MatLike) -> MatLike:
21
21
  :param img: 输入的饮品槽图像,大小 68x68 (BGR)
22
22
  :return: 处理后的图像,大小 68x68,其中会出现更大量的纯白色,便于识别
23
23
  """
24
- PREPROCESS_COLOR_THRESHOLD = 250
24
+ BLUE_THRESHOLD = 255
25
+ FLOOD_BLUE_THRESHOLD = 240
26
+ FLOOD_COLOR_THRESHOLD = 230
25
27
 
26
28
  assert img.shape[2] == 3
27
29
  h, w, _ = img.shape
@@ -30,7 +32,7 @@ def preprocess_drink_slot_img(img: MatLike) -> MatLike:
30
32
  b, g, r = cv2.split(img)
31
33
 
32
34
  # 把 b==255 的像素修正为纯白
33
- mask = (b >= PREPROCESS_COLOR_THRESHOLD)
35
+ mask = (b >= BLUE_THRESHOLD)
34
36
  g[mask] = 255
35
37
  b[mask] = 255
36
38
  r[mask] = 255
@@ -66,7 +68,7 @@ def preprocess_drink_slot_img(img: MatLike) -> MatLike:
66
68
  # 四邻域扩展
67
69
  for dy, dx in [(-1,0), (1,0), (0,-1), (0,1)]:
68
70
  ny, nx = y + dy, x + dx
69
- if 0 <= nx < w and 0 <= ny < h and not (nx > right_top_x and ny < right_top_y) and not visited[ny, nx] and not np.all(img[ny, nx] >= PREPROCESS_COLOR_THRESHOLD):
71
+ if 0 <= nx < w and 0 <= ny < h and not (nx > right_top_x and ny < right_top_y) and not visited[ny, nx] and not np.all(img[ny, nx] >= FLOOD_COLOR_THRESHOLD) and not (img[ny, nx][0] >= FLOOD_BLUE_THRESHOLD):
70
72
  q.append((ny, nx))
71
73
 
72
74
  return img
@@ -89,7 +91,12 @@ def match_first_drinks(img: MatLike, delta_threshold: float = 0.7) -> Drink | No
89
91
  :return: 若匹配成功,则返回 饮品的信息 和 前1~3个匹配饮品的数据库查询结果(用于更详细的日志输出);否则返回 None。
90
92
  """
91
93
 
94
+
95
+ # cv2.imshow("img", img)
92
96
  img = preprocess_drink_slot_img(img)
97
+ # cv2.imshow("img1", img)
98
+ # cv2.waitKey(0)
99
+ # cv2.destroyAllWindows()
93
100
 
94
101
  db = drinks_db()
95
102
  matches = db.match_all(img, threshold=114514)
@@ -157,10 +164,11 @@ if __name__ == '__main__':
157
164
  from logging import getLogger
158
165
  logging.basicConfig(level=logging.INFO, format='[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s')
159
166
 
160
- img = R.InPurodyuusu.Screenshot5Cards.data
161
- # img = R.InPurodyuusu.ScreenshotSenseiTipConsult.data
162
- # img = R.InPurodyuusu.Screenshot1Cards.data
167
+ # img = R.InPurodyuusu.Screenshot5Cards.data # len = 2
168
+ # img = R.InPurodyuusu.ScreenshotSenseiTipConsult.data # len = 3
169
+ # img = R.InPurodyuusu.Screenshot1Cards.data # len = 2
163
170
  # img = R.InPurodyuusu.ScreenshotDrinkTest.data # len = 2
164
171
  # img = R.InPurodyuusu.Screenshot4Cards.data # len = 0
172
+ img = R.InPurodyuusu.ScreenshotDrinkTest3.data # len = 1
165
173
  results = locate_all_drinks_in_3_drink_slots(img)
166
174
  print(len(results), ":", results)
kaa/main/gr.py CHANGED
@@ -20,6 +20,7 @@ from kaa.db import IdolCard
20
20
  from kotonebot.backend.context.context import vars
21
21
  from kotonebot.errors import ContextNotInitializedError
22
22
  from kotonebot.client.host import Mumu12Host, LeidianHost
23
+ from kotonebot.client.host.mumu12_host import Mumu12V5Host
23
24
  from kotonebot.config.manager import load_config, save_config
24
25
  from kotonebot.config.base_config import UserConfig, BackendConfig
25
26
  from kotonebot.backend.context import task_registry, ContextStackVars
@@ -42,7 +43,7 @@ ConfigKey = Literal[
42
43
  'screenshot_method', 'keep_screenshots',
43
44
  'check_emulator', 'emulator_path',
44
45
  'adb_emulator_name', 'emulator_args',
45
- '_mumu_index', '_leidian_index',
46
+ '_mumu_index', '_mumu12v5_index', '_leidian_index',
46
47
  'mumu_background_mode', 'target_screenshot_interval',
47
48
 
48
49
  # purchase
@@ -482,6 +483,7 @@ class KotoneBotUI:
482
483
 
483
484
  valid_screenshot_methods = {
484
485
  'mumu12': ['adb', 'adb_raw', 'uiautomator2', 'nemu_ipc'],
486
+ 'mumu12v5': ['adb', 'adb_raw', 'uiautomator2', 'nemu_ipc'],
485
487
  'leidian': ['adb', 'adb_raw', 'uiautomator2'],
486
488
  'custom': ['adb', 'adb_raw', 'uiautomator2'],
487
489
  'dmm': ['remote_windows', 'windows']
@@ -854,46 +856,78 @@ class KotoneBotUI:
854
856
  with gr.Tab("任务"):
855
857
  gr.Markdown("## 执行任务")
856
858
 
857
- # 创建任务选择下拉框
858
- task_choices = [task.name for task in task_registry.values()]
859
- task_dropdown = gr.Dropdown(
860
- choices=task_choices,
861
- label="选择要执行的任务",
862
- info="选择一个要单独执行的任务",
863
- type="value",
864
- value=None
865
- )
866
-
867
- # 创建执行按钮和暂停按钮
859
+ # 第一行:统一的停止和暂停按钮
868
860
  with gr.Row():
869
- execute_btn = gr.Button("执行任务", scale=2)
861
+ stop_all_btn = gr.Button("停止任务", variant="stop", scale=1)
870
862
  pause_btn = gr.Button("暂停", scale=1)
863
+
871
864
  task_result = gr.Markdown("")
872
865
 
873
- def toggle_single_task(task_name: str) -> Tuple[gr.Button, str]:
866
+ # 获取所有任务并创建列表布局
867
+ tasks = list(task_registry.values())
868
+ task_buttons = [] # 存储所有任务按钮的引用
869
+
870
+ # 为每个任务创建一行:左侧启动按钮,右侧任务名
871
+ for task in tasks:
872
+ with gr.Row():
873
+ with gr.Column(scale=1, min_width=50):
874
+ task_btn = gr.Button("启动", variant="primary", size="sm")
875
+ task_buttons.append((task_btn, task.name))
876
+ with gr.Column(scale=7):
877
+ gr.Markdown(f"{task.name}")
878
+
879
+ # 事件处理函数
880
+ def start_single_task_by_name(task_name: str):
881
+ """启动指定任务并返回状态信息及所有按钮的更新状态"""
874
882
  if self.single_task_running:
875
- # 如果正在停止过程中,忽略重复点击
876
- if self.is_single_task_stopping:
877
- return gr.Button(value="停止中...", interactive=False), "正在停止任务..."
883
+ return ["已有任务正在运行"] + [gr.Button(interactive=False) for _ in task_buttons]
884
+
885
+ # 启动任务
886
+ result = self.start_single_task(task_name)
887
+ status_msg = result[1]
888
+
889
+ # 如果成功启动,禁用所有任务按钮
890
+ if self.single_task_running:
891
+ disabled_buttons = [gr.Button(value="运行中", interactive=False) for _ in task_buttons]
892
+ else:
893
+ disabled_buttons = [gr.Button(value="启动", interactive=True) for _ in task_buttons]
894
+
895
+ return [status_msg] + disabled_buttons
878
896
 
879
- result = self.stop_single_task()
880
- return gr.Button(value=result[0], interactive=False), result[1]
897
+ def stop_all_tasks():
898
+ """停止所有任务并重置按钮状态"""
899
+ if not self.single_task_running:
900
+ return ["没有正在运行的任务"] + [gr.Button(value="启动", interactive=True) for _ in task_buttons]
901
+
902
+ # 停止任务
903
+ result = self.stop_single_task()
904
+ status_msg = result[1]
905
+
906
+ # 如果正在停止中,显示停止中状态
907
+ if self.is_single_task_stopping:
908
+ disabled_buttons = [gr.Button(value="停止中", interactive=False) for _ in task_buttons]
881
909
  else:
882
- result = self.start_single_task(task_name)
883
- return gr.Button(value=result[0], interactive=True), result[1]
910
+ disabled_buttons = [gr.Button(value="启动", interactive=True) for _ in task_buttons]
911
+
912
+ return [status_msg] + disabled_buttons
884
913
 
885
- def get_task_button_status() -> gr.Button:
914
+ def get_task_buttons_status() -> List[gr.Button]:
915
+ """获取所有任务按钮的状态"""
886
916
  if not hasattr(self, 'run_status') or not self.run_status.running:
887
917
  self.single_task_running = False
888
- self.is_single_task_stopping = False # 重置停止状态
889
- return gr.Button(value="执行任务", interactive=True)
918
+ self.is_single_task_stopping = False
919
+ return [gr.Button(value="启动", interactive=True) for _ in task_buttons]
890
920
 
891
921
  if self.is_single_task_stopping:
892
- return gr.Button(value="停止中...", interactive=False) # 停止中时禁用按钮
922
+ return [gr.Button(value="停止中", interactive=False) for _ in task_buttons]
923
+
924
+ if self.single_task_running:
925
+ return [gr.Button(value="运行中", interactive=False) for _ in task_buttons]
893
926
 
894
- return gr.Button(value="停止任务", interactive=True)
927
+ return [gr.Button(value="启动", interactive=True) for _ in task_buttons]
895
928
 
896
929
  def get_single_task_status() -> str:
930
+ """获取任务状态信息"""
897
931
  if not hasattr(self, 'run_status'):
898
932
  return ""
899
933
 
@@ -924,15 +958,29 @@ class KotoneBotUI:
924
958
 
925
959
  return ""
926
960
 
927
- def on_pause_click(evt: gr.EventData) -> str:
961
+ def on_pause_click() -> str:
928
962
  return self.toggle_pause()
929
963
 
930
- execute_btn.click(
931
- fn=toggle_single_task,
932
- inputs=[task_dropdown],
933
- outputs=[execute_btn, task_result]
964
+ # 绑定事件 - 为每个任务按钮绑定点击事件
965
+ def create_task_handler(task_name: str):
966
+ """创建任务处理函数,避免闭包问题"""
967
+ def handler():
968
+ return start_single_task_by_name(task_name)
969
+ return handler
970
+
971
+ for task_btn, task_name in task_buttons:
972
+ task_btn.click(
973
+ fn=create_task_handler(task_name),
974
+ outputs=[task_result] + [btn for btn, _ in task_buttons]
975
+ )
976
+
977
+ # 绑定停止按钮事件
978
+ stop_all_btn.click(
979
+ fn=stop_all_tasks,
980
+ outputs=[task_result] + [btn for btn, _ in task_buttons]
934
981
  )
935
982
 
983
+ # 绑定暂停按钮事件
936
984
  pause_btn.click(
937
985
  fn=on_pause_click,
938
986
  outputs=[pause_btn]
@@ -940,8 +988,8 @@ class KotoneBotUI:
940
988
 
941
989
  # 添加定时器更新按钮状态和任务状态
942
990
  gr.Timer(1.0).tick(
943
- fn=get_task_button_status,
944
- outputs=[execute_btn]
991
+ fn=get_task_buttons_status,
992
+ outputs=[btn for btn, _ in task_buttons]
945
993
  )
946
994
  gr.Timer(1.0).tick(
947
995
  fn=self.get_pause_button_with_interactive,
@@ -967,8 +1015,8 @@ class KotoneBotUI:
967
1015
  return new_value
968
1016
 
969
1017
  with gr.Tabs(selected=self.current_config.backend.type):
970
- with gr.Tab("MuMu 12", id="mumu12") as tab_mumu12:
971
- gr.Markdown("已选中 MuMu 12 模拟器")
1018
+ with gr.Tab("MuMu 12 v4.x", id="mumu12") as tab_mumu12:
1019
+ gr.Markdown("已选中 MuMu 12 v4.x 模拟器")
972
1020
  mumu_refresh_message = gr.Markdown("<div style='color: red;'>点击下方「刷新」按钮载入信息</div>", visible=True)
973
1021
  mumu_instance = gr.Dropdown(
974
1022
  label="选择多开实例",
@@ -1012,6 +1060,51 @@ class KotoneBotUI:
1012
1060
  interactive=True
1013
1061
  )
1014
1062
 
1063
+ with gr.Tab("MuMu 12 v5.x", id="mumu12v5") as tab_mumu12v5:
1064
+ gr.Markdown("已选中 MuMu 12 v5.x 模拟器")
1065
+ mumu_refresh_message = gr.Markdown("<div style='color: red;'>点击下方「刷新」按钮载入信息</div>", visible=True)
1066
+ mumu_instance12v5 = gr.Dropdown(
1067
+ label="选择多开实例",
1068
+ choices=[],
1069
+ interactive=True
1070
+ )
1071
+ mumu_refresh_btn = gr.Button("刷新")
1072
+
1073
+ def refresh_mumu12v5_instances():
1074
+ try:
1075
+ instances = Mumu12V5Host.list()
1076
+ is_mumu12v5 = self.current_config.backend.type == 'mumu12v5'
1077
+ current_id = self.current_config.backend.instance_id if is_mumu12v5 else None
1078
+ choices = [(i.name, i.id) for i in instances]
1079
+ return gr.Dropdown(choices=choices, value=current_id, interactive=True), gr.Markdown(visible=False)
1080
+ except Exception as e:
1081
+ logger.exception('Failed to list installed MuMu12v5')
1082
+ gr.Error("获取 MuMu12 模拟器列表失败,请升级模拟器到最新版本。若问题依旧,前往 QQ 群、QQ 频道或 Github 反馈 bug。")
1083
+ return gr.Dropdown(choices=[], interactive=True), gr.Markdown(visible=True)
1084
+
1085
+ mumu_refresh_btn.click(
1086
+ fn=refresh_mumu12v5_instances,
1087
+ outputs=[mumu_instance12v5, mumu_refresh_message]
1088
+ )
1089
+
1090
+ # 如果当前是 MuMu 模拟器且有配置的 instance_id,立即加载实例列表
1091
+ if self.current_config.backend.type == 'mumu12v5' and self.current_config.backend.instance_id:
1092
+ try:
1093
+ instances = Mumu12V5Host.list()
1094
+ choices = [(i.name, i.id) for i in instances]
1095
+ mumu_instance12v5.choices = choices
1096
+ mumu_instance12v5.value = self.current_config.backend.instance_id
1097
+ mumu_refresh_message.visible = False
1098
+ except Exception as e:
1099
+ logger.exception('Failed to auto-load MuMu12v5 instances')
1100
+
1101
+ mumu_background_mode = gr.Checkbox(
1102
+ label="MuMu12v5 模拟器后台保活模式",
1103
+ value=self.current_config.backend.mumu_background_mode,
1104
+ info=BackendConfig.model_fields['mumu_background_mode'].description,
1105
+ interactive=True
1106
+ )
1107
+
1015
1108
  with gr.Tab("雷电", id="leidian") as tab_leidian:
1016
1109
  gr.Markdown("已选中雷电模拟器")
1017
1110
  leidian_refresh_message = gr.Markdown("<div style='color: red;'>点击下方「刷新」按钮载入信息</div>", visible=True)
@@ -1101,6 +1194,7 @@ class KotoneBotUI:
1101
1194
 
1102
1195
  with gr.Tab("DMM", id="dmm") as tab_dmm:
1103
1196
  gr.Markdown("已选中 DMM")
1197
+ gr.Markdown("**暂停快捷键 <kbd>Ctrl</kbd> + <kbd>F4</kbd>,停止快捷键 <kbd>Ctrl</kbd> + <kbd>F3</kbd>**")
1104
1198
 
1105
1199
  choices = ['adb', 'adb_raw', 'uiautomator2', 'windows', 'remote_windows', 'nemu_ipc']
1106
1200
  screenshot_impl = gr.Dropdown(
@@ -1122,6 +1216,7 @@ class KotoneBotUI:
1122
1216
  )
1123
1217
 
1124
1218
  tab_mumu12.select(fn=partial(_update_emulator_tab_options, selected_index=0), inputs=[screenshot_impl], outputs=[screenshot_impl])
1219
+ tab_mumu12v5.select(fn=partial(_update_emulator_tab_options, selected_index=1), inputs=[screenshot_impl], outputs=[screenshot_impl])
1125
1220
  tab_leidian.select(fn=partial(_update_emulator_tab_options, selected_index=1), inputs=[screenshot_impl], outputs=[screenshot_impl])
1126
1221
  tab_custom.select(fn=partial(_update_emulator_tab_options, selected_index=2), inputs=[screenshot_impl], outputs=[screenshot_impl])
1127
1222
  tab_dmm.select(fn=partial(_update_emulator_tab_options, selected_index=3), inputs=[screenshot_impl], outputs=[screenshot_impl])
@@ -1132,21 +1227,26 @@ class KotoneBotUI:
1132
1227
  impl_value=self.current_config.backend.screenshot_impl,
1133
1228
  selected_index=0
1134
1229
  )
1135
- elif self.current_config.backend.type == 'leidian':
1230
+ elif self.current_config.backend.type == 'mumu12v5':
1136
1231
  _update_emulator_tab_options(
1137
1232
  impl_value=self.current_config.backend.screenshot_impl,
1138
1233
  selected_index=1
1139
1234
  )
1140
- elif self.current_config.backend.type == 'custom':
1235
+ elif self.current_config.backend.type == 'leidian':
1141
1236
  _update_emulator_tab_options(
1142
1237
  impl_value=self.current_config.backend.screenshot_impl,
1143
1238
  selected_index=2
1144
1239
  )
1145
- elif self.current_config.backend.type == 'dmm':
1240
+ elif self.current_config.backend.type == 'custom':
1146
1241
  _update_emulator_tab_options(
1147
1242
  impl_value=self.current_config.backend.screenshot_impl,
1148
1243
  selected_index=3
1149
1244
  )
1245
+ elif self.current_config.backend.type == 'dmm':
1246
+ _update_emulator_tab_options(
1247
+ impl_value=self.current_config.backend.screenshot_impl,
1248
+ selected_index=4
1249
+ )
1150
1250
  else:
1151
1251
  gr.Warning(f"未知的模拟器类型:{self.current_config.backend.type}")
1152
1252
 
@@ -1156,10 +1256,15 @@ class KotoneBotUI:
1156
1256
  self.current_config.backend.type = 'mumu12'
1157
1257
  self.current_config.backend.instance_id = data['_mumu_index']
1158
1258
  self.current_config.backend.mumu_background_mode = data['mumu_background_mode']
1159
- elif current_tab == 1: # Leidian
1259
+ elif current_tab == 1: # Mumu12v5
1260
+ # TODO: 由于 backend 类型放在了 Kotonebot 里,现在无法扩展,后续需要移出来
1261
+ self.current_config.backend.type = 'mumu12v5'
1262
+ self.current_config.backend.instance_id = data['_mumu12v5_index']
1263
+ self.current_config.backend.mumu_background_mode = data['mumu_background_mode']
1264
+ elif current_tab == 2: # Leidian
1160
1265
  self.current_config.backend.type = 'leidian'
1161
1266
  self.current_config.backend.instance_id = data['_leidian_index']
1162
- elif current_tab == 2: # Custom
1267
+ elif current_tab == 3: # Custom
1163
1268
  self.current_config.backend.type = 'custom'
1164
1269
  self.current_config.backend.instance_id = None
1165
1270
  self.current_config.backend.adb_ip = data['adb_ip']
@@ -1168,7 +1273,7 @@ class KotoneBotUI:
1168
1273
  self.current_config.backend.check_emulator = data['check_emulator']
1169
1274
  self.current_config.backend.emulator_path = data['emulator_path']
1170
1275
  self.current_config.backend.emulator_args = data['emulator_args']
1171
- elif current_tab == 3: # DMM
1276
+ elif current_tab == 4: # DMM
1172
1277
  self.current_config.backend.type = 'dmm'
1173
1278
  self.current_config.backend.instance_id = None # DMM doesn't use instance_id here
1174
1279
 
@@ -1187,6 +1292,7 @@ class KotoneBotUI:
1187
1292
  'emulator_args': emulator_args,
1188
1293
  '_mumu_index': mumu_instance,
1189
1294
  '_leidian_index': leidian_instance,
1295
+ '_mumu12v5_index': mumu_instance12v5,
1190
1296
  'mumu_background_mode': mumu_background_mode
1191
1297
  }
1192
1298
 
@@ -2570,7 +2676,63 @@ class KotoneBotUI:
2570
2676
  def list_all_versions():
2571
2677
  """列出所有可用版本"""
2572
2678
  import logging
2679
+ import re
2573
2680
  logger = logging.getLogger(__name__)
2681
+
2682
+ # 检查启动器版本
2683
+ def check_launcher_version():
2684
+ """通过读取bootstrap.pyz/meta.py获取启动器版本"""
2685
+ import zipfile
2686
+ try:
2687
+ bootstrap_path = os.path.join(os.getcwd(), "bootstrap.pyz")
2688
+ if not os.path.exists(bootstrap_path):
2689
+ logger.warning("启动器文件不存在")
2690
+ gr.Warning("启动器文件不存在")
2691
+ return None
2692
+
2693
+ # 尝试从bootstrap.pyz中读取meta.py
2694
+ try:
2695
+ with zipfile.ZipFile(bootstrap_path, 'r') as zip_file:
2696
+ if 'meta.py' in zip_file.namelist():
2697
+ # 读取meta.py内容
2698
+ meta_content = zip_file.read('meta.py').decode('utf-8')
2699
+
2700
+ # 创建一个安全的执行环境
2701
+ exec_globals = {}
2702
+ exec_locals = {}
2703
+
2704
+ # 执行meta.py内容
2705
+ exec(meta_content, exec_globals, exec_locals)
2706
+
2707
+ # 获取VERSION变量
2708
+ if 'VERSION' in exec_locals:
2709
+ version = exec_locals['VERSION']
2710
+ # 移除v前缀(如果有)
2711
+ if isinstance(version, str) and version.startswith('v'):
2712
+ version = version[1:]
2713
+ logger.info(f"从meta.py读取到启动器版本: {version}")
2714
+ return str(version)
2715
+ else:
2716
+ logger.warning("meta.py中未找到VERSION变量")
2717
+ gr.Warning("meta.py中未找到VERSION变量")
2718
+ return None
2719
+ else:
2720
+ logger.warning("bootstrap.pyz中未找到meta.py文件")
2721
+ gr.Warning("bootstrap.pyz中未找到meta.py文件")
2722
+ return None
2723
+ except zipfile.BadZipFile:
2724
+ # 不是有效的zip文件,可能是旧版本启动器
2725
+ logger.info("bootstrap.pyz不是有效的zip文件,判断为旧版本启动器")
2726
+ return "0.4.x"
2727
+ except Exception as e:
2728
+ logger.warning(f"读取bootstrap.pyz失败: {str(e)}")
2729
+ gr.Warning(f"读取bootstrap.pyz失败: {str(e)}")
2730
+ return None
2731
+
2732
+ except Exception as e:
2733
+ logger.warning(f"检查启动器版本失败: {str(e)}")
2734
+ gr.Warning(f"检查启动器版本失败: {str(e)}")
2735
+ return None
2574
2736
 
2575
2737
  try:
2576
2738
  # 构建命令,使用清华镜像源
@@ -2636,12 +2798,22 @@ class KotoneBotUI:
2636
2798
  gr.Button(visible=False)
2637
2799
  )
2638
2800
 
2801
+ # 检查启动器版本
2802
+ launcher_version = check_launcher_version()
2803
+
2639
2804
  # 构建状态信息
2640
2805
  status_info = []
2641
2806
  if installed_version:
2642
2807
  status_info.append(f"**当前安装版本:** {installed_version}")
2643
2808
  if latest_version:
2644
2809
  status_info.append(f"**最新版本:** {latest_version}")
2810
+ if launcher_version:
2811
+ if launcher_version == "0.4.x":
2812
+ status_info.append(f"**启动器版本:** < v0.5.0 (旧版本)")
2813
+ else:
2814
+ status_info.append(f"**启动器版本:** v{launcher_version}")
2815
+ else:
2816
+ status_info.append(f"**启动器版本:** 未知")
2645
2817
  status_info.append(f"**找到 {len(versions)} 个可用版本**")
2646
2818
 
2647
2819
  status_message = "\n\n".join(status_info)
@@ -2679,12 +2851,130 @@ class KotoneBotUI:
2679
2851
  import logging
2680
2852
  import threading
2681
2853
  import time
2854
+ import re
2682
2855
  logger = logging.getLogger(__name__)
2683
2856
 
2684
2857
  if not selected_version:
2685
2858
  error_msg = "请先选择一个版本"
2686
2859
  logger.warning(error_msg)
2687
2860
  return error_msg
2861
+
2862
+
2863
+ def compare_version(version1: str, version2: str) -> int:
2864
+ """比较版本号,返回-1(v1<v2), 0(v1==v2), 1(v1>v2)"""
2865
+ # 处理特殊标记
2866
+ if version1 == "0.4.x":
2867
+ version1 = "0.4.0"
2868
+
2869
+ def parse_version(v):
2870
+ # 移除v前缀并解析版本号和预发布标识
2871
+ v = v.lstrip('v')
2872
+ if 'b' in v:
2873
+ base, beta = v.split('b', 1)
2874
+ return tuple(map(int, base.split('.'))) + (-1, int(beta))
2875
+ elif 'a' in v:
2876
+ base, alpha = v.split('a', 1)
2877
+ return tuple(map(int, base.split('.'))) + (-2, int(alpha))
2878
+ elif 'rc' in v:
2879
+ base, rc = v.split('rc', 1)
2880
+ return tuple(map(int, base.split('.'))) + (-0.5, int(rc))
2881
+ else:
2882
+ return tuple(map(int, v.split('.'))) + (0, 0)
2883
+
2884
+ v1_parsed = parse_version(version1)
2885
+ v2_parsed = parse_version(version2)
2886
+
2887
+ if v1_parsed < v2_parsed:
2888
+ return -1
2889
+ elif v1_parsed > v2_parsed:
2890
+ return 1
2891
+ else:
2892
+ return 0
2893
+
2894
+ # 检查启动器版本进行兼容性验证
2895
+ def check_launcher_version_simple():
2896
+ """通过读取bootstrap.pyz/meta.py获取启动器版本"""
2897
+ import zipfile
2898
+ try:
2899
+ bootstrap_path = os.path.join(os.getcwd(), "bootstrap.pyz")
2900
+ if not os.path.exists(bootstrap_path):
2901
+ logger.warning("启动器文件不存在")
2902
+ gr.Warning("启动器文件不存在")
2903
+ return None
2904
+
2905
+ # 尝试从bootstrap.pyz中读取meta.py
2906
+ try:
2907
+ with zipfile.ZipFile(bootstrap_path, 'r') as zip_file:
2908
+ if 'meta.py' in zip_file.namelist():
2909
+ # 读取meta.py内容
2910
+ meta_content = zip_file.read('meta.py').decode('utf-8')
2911
+
2912
+ # 创建一个安全的执行环境
2913
+ exec_globals = {}
2914
+ exec_locals = {}
2915
+
2916
+ # 执行meta.py内容
2917
+ exec(meta_content, exec_globals, exec_locals)
2918
+
2919
+ # 获取VERSION变量
2920
+ if 'VERSION' in exec_locals:
2921
+ version = exec_locals['VERSION']
2922
+ # 移除v前缀(如果有)
2923
+ if isinstance(version, str) and version.startswith('v'):
2924
+ version = version[1:]
2925
+ logger.info(f"从meta.py读取到启动器版本: {version}")
2926
+ return str(version)
2927
+ else:
2928
+ logger.warning("meta.py中未找到VERSION变量")
2929
+ gr.Warning("meta.py中未找到VERSION变量")
2930
+ return None
2931
+ else:
2932
+ logger.warning("bootstrap.pyz中未找到meta.py文件")
2933
+ gr.Warning("bootstrap.pyz中未找到meta.py文件")
2934
+ return None
2935
+ except zipfile.BadZipFile:
2936
+ # 不是有效的zip文件,可能是旧版本启动器
2937
+ logger.info("bootstrap.pyz不是有效的zip文件,判断为旧版本启动器")
2938
+ return "0.4.x"
2939
+ except Exception as e:
2940
+ logger.warning(f"读取bootstrap.pyz失败: {str(e)}")
2941
+ gr.Warning(f"读取bootstrap.pyz失败: {str(e)}")
2942
+ return None
2943
+
2944
+ except Exception as e:
2945
+ logger.warning(f"检查启动器版本失败: {str(e)}")
2946
+ gr.Warning(f"检查启动器版本失败: {str(e)}")
2947
+ return None
2948
+
2949
+ # 执行启动器版本检查
2950
+ launcher_version = check_launcher_version_simple()
2951
+ logger.info(f"检测到启动器版本: {launcher_version}")
2952
+
2953
+ # 版本兼容性检查
2954
+ if launcher_version:
2955
+ if compare_version(launcher_version, "0.5.0") < 0:
2956
+ # 启动器版本低于0.5.0
2957
+ logger.warning(f"启动器版本 {launcher_version} 低于 v0.5.0")
2958
+
2959
+ # 检查要安装的版本是否 >= v2025.9b1
2960
+ if compare_version(selected_version, "2025.9b1") >= 0:
2961
+ error_msg = (
2962
+ f"❌ 版本兼容性错误\n\n"
2963
+ f"启动器版本: {launcher_version}\n"
2964
+ f"要安装的版本: {selected_version}\n\n"
2965
+ f"v2025.9b1 及以上版本需要**启动器 v0.5.0*** 或更高版本支持。\n"
2966
+ f"请先升级启动器到 v0.5.0 以上版本。[查看帮助](https://www.kdocs.cn/l/cetCY8mGKHLj?linkname=UhPH1itaSv)"
2967
+ )
2968
+ logger.error(error_msg)
2969
+ return error_msg
2970
+ else:
2971
+ # 版本兼容,但给出警告
2972
+ logger.warning(f"启动器版本较低,建议升级到 v0.5.0 以上")
2973
+ gr.Warning("启动器版本较低,建议升级到 v0.5.0 以上")
2974
+ else:
2975
+ # 无法获取启动器版本,给出警告但继续
2976
+ logger.warning("无法获取启动器版本,可以继续安装但可能存在兼容性问题")
2977
+ gr.Warning("无法获取启动器版本,可以继续安装但可能存在兼容性问题")
2688
2978
 
2689
2979
  def install_and_exit():
2690
2980
  """在后台线程中执行安装并退出程序"""
@@ -2705,9 +2995,6 @@ class KotoneBotUI:
2705
2995
  creationflags=subprocess.CREATE_NEW_CONSOLE if os.name == 'nt' else 0
2706
2996
  )
2707
2997
 
2708
- # 等待一小段时间确保启动器启动
2709
- time.sleep(2)
2710
-
2711
2998
  # 退出当前程序
2712
2999
  logger.info("安装即将开始,正在退出当前程序...")
2713
3000
  os._exit(0)