ksaa 2025.8.2.0__py3-none-any.whl → 2025.8.17.0__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.
- kotonebot/backend/loop.py +276 -276
- kotonebot/kaa/main/gr.py +5 -23
- kotonebot/kaa/metadata.py +12 -0
- kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
- kotonebot/kaa/resources/game.db +0 -0
- kotonebot/kaa/resources/game_ver.txt +0 -0
- kotonebot/kaa/resources/idol_cards/i_card-skin-fktn-3-013_0.png +0 -0
- kotonebot/kaa/resources/idol_cards/i_card-skin-fktn-3-013_1.png +0 -0
- kotonebot/kaa/tasks/R.py +126 -126
- kotonebot/kaa/tasks/daily/purchase.py +9 -2
- {ksaa-2025.8.2.0.dist-info → ksaa-2025.8.17.0.dist-info}/METADATA +1 -1
- {ksaa-2025.8.2.0.dist-info → ksaa-2025.8.17.0.dist-info}/RECORD +142 -140
- /kotonebot/kaa/sprites/{d2bce7a9-8709-4042-a31a-1f07b2711637.png → 00a2e0d4-1683-4c36-88df-081673e2fe1a.png} +0 -0
- /kotonebot/kaa/sprites/{9169b74f-7458-4562-bc90-41efe0edfc22.png → 07578d0c-15d4-42a2-9db1-a1c0c11b55c1.png} +0 -0
- /kotonebot/kaa/sprites/{66cc412b-a4a1-4b42-89b4-7653eef41204.png → 079cdbed-7171-42e3-8298-9d1e180982ec.png} +0 -0
- /kotonebot/kaa/sprites/{b7bd78a1-aa4a-4847-8e9a-969989ef3cb3.png → 07c5517b-38f7-44e6-8506-84317ba0fb86.png} +0 -0
- /kotonebot/kaa/sprites/{9ce465b3-b4a6-4646-a559-3088621a1da1.png → 07d78d3e-4e79-459e-9c41-43f4a618f9e9.png} +0 -0
- /kotonebot/kaa/sprites/{1935d9dc-84ff-47a8-a65b-a458a224b4cc.png → 0899e636-b767-45e6-ab63-258d19d3f806.png} +0 -0
- /kotonebot/kaa/sprites/{b6da32be-5c6d-40a8-b1d0-15e0576c6f71.png → 0b27cdd2-490b-4a6a-ae0d-788ac1601dcc.png} +0 -0
- /kotonebot/kaa/sprites/{e97c5043-a73e-4979-a529-34b4daaee88d.png → 0b947c81-0ab1-40a8-8c26-26258be572c7.png} +0 -0
- /kotonebot/kaa/sprites/{133ea490-fefe-4785-b531-3cc7072338da.png → 0da004d8-2cc5-43ab-9ac1-94d4f74dd37d.png} +0 -0
- /kotonebot/kaa/sprites/{de804900-3470-478e-a51f-e3919b301326.png → 0de1fa4d-3621-4671-9e1f-b8ed1e767adc.png} +0 -0
- /kotonebot/kaa/sprites/{22394de7-f95b-4001-a961-d854c34f1d8c.png → 0e998848-beb2-4d31-9019-6afab9e0180e.png} +0 -0
- /kotonebot/kaa/sprites/{644a3f8a-6b32-4c3e-9701-acb426502f81.png → 0ef0615f-f293-4a4e-93ac-985b3a17c8d7.png} +0 -0
- /kotonebot/kaa/sprites/{5da76978-7dc4-4d4e-8e4c-e3189e2c2b07.png → 1135ed8d-4e1c-4896-9d6d-5c2ba3d29761.png} +0 -0
- /kotonebot/kaa/sprites/{73c270f5-055a-4cc3-9036-c95321faec4a.png → 12b811a3-5b37-4510-9ebd-95455644f253.png} +0 -0
- /kotonebot/kaa/sprites/{785837db-1da3-46d0-866f-017c232547ad.png → 130ee78a-c201-4fa0-bac5-7be0b842312d.png} +0 -0
- /kotonebot/kaa/sprites/{9acf0817-ab1f-45e1-a26f-99c3c331a184.png → 1339693d-6e77-4058-921a-9079c8eb5a9a.png} +0 -0
- /kotonebot/kaa/sprites/{ab823208-66f4-4a97-836b-024bf27b7c74.png → 141b5f13-489d-4271-ac49-4d0bd40bf8fc.png} +0 -0
- /kotonebot/kaa/sprites/{fe9a7ad5-4506-4dfe-80a5-6f4bb9703f9c.png → 14488bad-1e16-47b8-9870-f2e18c6b87ee.png} +0 -0
- /kotonebot/kaa/sprites/{ed84a435-c52c-4294-ad80-bf3c63e2878d.png → 1466ba09-8e27-49cd-8606-f9feeecc2915.png} +0 -0
- /kotonebot/kaa/sprites/{df11deb8-940d-45a3-89b7-48c814735448.png → 15ce2944-3d27-4073-b969-2ec8fc98ceb4.png} +0 -0
- /kotonebot/kaa/sprites/{72ea8e77-8773-47bf-9c5f-bf51812065cd.png → 1777dfb5-2793-4037-9da7-f789cf65896e.png} +0 -0
- /kotonebot/kaa/sprites/{0450fdf0-f03d-4efc-b047-27532571c620.png → 1abdc520-6123-40c9-bf50-d84e46f9420c.png} +0 -0
- /kotonebot/kaa/sprites/{727c2d86-0daf-47d3-8eb4-500e648abfd6.png → 1ae6b793-d85f-4b06-ba9f-bdb7fbed26fc.png} +0 -0
- /kotonebot/kaa/sprites/{1564ee9a-c2eb-4284-b22a-dd8df7c8a32f.png → 1d5835f8-593c-4ec4-a360-81fce8d2f959.png} +0 -0
- /kotonebot/kaa/sprites/{ddb5b885-93de-49d1-8150-3235d702c1c8.png → 1e540586-c381-4aed-b689-e9cd2708ae85.png} +0 -0
- /kotonebot/kaa/sprites/{9713c534-6f51-45c7-a03c-1acb642c519c.png → 1f8cca6a-ae0a-44c9-a267-989ae508320a.png} +0 -0
- /kotonebot/kaa/sprites/{55e853dd-07bc-4086-8a2d-60d24ff75839.png → 214fad37-3e64-4786-8cfa-b48dd49ddbe4.png} +0 -0
- /kotonebot/kaa/sprites/{969ddfa4-c0c8-41c8-b51b-40febf152c7a.png → 21f2fdd8-c6fe-44fe-bcc6-efa8bc7f895a.png} +0 -0
- /kotonebot/kaa/sprites/{b144b5df-c3b5-4bda-bb3d-9c8fa1182080.png → 255b0e7a-c47a-4f70-9c92-5e3fa06d4d4c.png} +0 -0
- /kotonebot/kaa/sprites/{1193a4e3-4d0d-4433-97ce-b19aeb6846c5.png → 2ac9bca3-aad6-4d19-a4b7-4d7197d95fba.png} +0 -0
- /kotonebot/kaa/sprites/{a9c016ed-463b-4e06-88ce-020c2b4dd981.png → 2c43b51a-7ca5-4401-a05f-d3b3de17c2d3.png} +0 -0
- /kotonebot/kaa/sprites/{9d61082b-7e07-4da2-9210-5744a2481da4.png → 2e279b36-1057-453f-9a7e-7ac61ddce6f9.png} +0 -0
- /kotonebot/kaa/sprites/{50ca8582-8787-45ff-a6b6-e1f0e8b44cb5.png → 2e5cfcf0-34fc-4b17-9283-0c269d04ae98.png} +0 -0
- /kotonebot/kaa/sprites/{c0adda90-8b05-4a6b-b091-9d2c9d4b84f8.png → 32d066ef-5783-4ab4-8a41-5e948169b1d7.png} +0 -0
- /kotonebot/kaa/sprites/{c85ba9aa-9ff1-42a4-b80a-ef39ab009e85.png → 3303b048-552d-4794-aa57-180b43187d5a.png} +0 -0
- /kotonebot/kaa/sprites/{88e9493c-0914-489a-9d99-addff4f0efd0.png → 3336498e-763b-4b43-9939-a271d2deb64f.png} +0 -0
- /kotonebot/kaa/sprites/{b1c80e35-8949-4425-8b96-1df803cacde5.png → 350736d7-0774-4a48-973c-d9373fc68ea3.png} +0 -0
- /kotonebot/kaa/sprites/{356f4aa8-ebc5-4edc-9724-badf6d02d61e.png → 368d245a-8777-437a-80c4-e6b0504236e6.png} +0 -0
- /kotonebot/kaa/sprites/{7c6dd46a-62ff-4d2c-b04a-df97ba55ed74.png → 394c60cc-1caa-4a29-a387-798316d48d4a.png} +0 -0
- /kotonebot/kaa/sprites/{891d4f63-df7f-462c-8908-ff4380c91b8b.png → 3bf9aa00-7c6d-46ec-b487-7f846588acbe.png} +0 -0
- /kotonebot/kaa/sprites/{57c8fe6f-e970-4364-9359-9c273ca37b85.png → 4183bf72-4ca7-4480-a6db-c81632b1a62b.png} +0 -0
- /kotonebot/kaa/sprites/{d9b23b65-6780-446b-950c-48ca668f838a.png → 42092d5b-d11d-4651-9cd5-49302f52d50b.png} +0 -0
- /kotonebot/kaa/sprites/{9fa1e59d-36cb-43c9-a788-ed95ae93f3d0.png → 4365cb24-54a1-4998-8a2e-bed02fc988f5.png} +0 -0
- /kotonebot/kaa/sprites/{5ac654b1-f891-46b4-a4b2-3b8f9a60a02b.png → 471d7204-23f3-4d72-a852-77e8b424ddff.png} +0 -0
- /kotonebot/kaa/sprites/{14cd7285-f587-49af-9960-802c41050201.png → 48fc4fee-0d6e-4995-8d29-37791d33759e.png} +0 -0
- /kotonebot/kaa/sprites/{a9e90b22-4415-44cf-bf2f-6acb2733312f.png → 49fa1fd6-8115-476d-aa60-2d63613ef931.png} +0 -0
- /kotonebot/kaa/sprites/{0300702d-1023-4af7-9fee-54c058f7f1a8.png → 4c07fc6b-662a-4216-b1e6-6036fa6f717d.png} +0 -0
- /kotonebot/kaa/sprites/{39ab37d4-2654-4102-ba75-17d6bbd79673.png → 4c2fe337-73f6-4ed4-84ae-f17bf4787645.png} +0 -0
- /kotonebot/kaa/sprites/{4a395a76-b1b6-4541-97b0-2e2603d47360.png → 54a7603e-fd84-4d7f-99ef-f95d3695aa42.png} +0 -0
- /kotonebot/kaa/sprites/{1c0c3381-4d9b-4279-ac89-784b9e9d7e63.png → 54e4f9a3-3ae6-4bf4-85b1-680889835137.png} +0 -0
- /kotonebot/kaa/sprites/{fbea0ab6-3094-438e-807d-5a24d0d32cf3.png → 550c0ad2-4c38-4c34-8be2-9ea278b3f822.png} +0 -0
- /kotonebot/kaa/sprites/{1ec343a7-f6d4-4ab5-967b-66f900438977.png → 5b3f7210-d28b-4117-a664-efb790eec911.png} +0 -0
- /kotonebot/kaa/sprites/{43c175e2-7e7e-405a-8c92-0cf3d7400d12.png → 6224165f-3fa9-483f-b4fb-73c44e8009e4.png} +0 -0
- /kotonebot/kaa/sprites/{5bf54b6d-d2b6-4211-b3f4-0713b84dd315.png → 63b1d3d9-a0d7-413e-8e67-215ee46e5af7.png} +0 -0
- /kotonebot/kaa/sprites/{2b225eb3-c1b2-415a-99de-1a41a0ed4470.png → 64d7e162-a761-458b-a0c6-083658141032.png} +0 -0
- /kotonebot/kaa/sprites/{d400ab2d-b4dc-43bb-bb77-f49c666bf4b1.png → 6b33fe3c-28ff-49ad-ba24-7279c8e9ec19.png} +0 -0
- /kotonebot/kaa/sprites/{5c2e3a85-838c-41d5-b55e-b62fc1b95a1e.png → 6b4f820d-8b40-4ac1-9322-550860cbda08.png} +0 -0
- /kotonebot/kaa/sprites/{6b2bd35a-d399-4486-b4ef-24abb3e6669f.png → 6ede6499-0efe-4ad2-83c7-5fd8a512c52e.png} +0 -0
- /kotonebot/kaa/sprites/{c75bba52-b3a5-4565-bb45-104ebed9e3d2.png → 71293cd1-83de-4f15-9608-1d31678e3566.png} +0 -0
- /kotonebot/kaa/sprites/{2a317f0e-613e-48c4-9def-d18a3b834254.png → 71ce4a03-5865-47fb-a2a2-d220dbd8ead3.png} +0 -0
- /kotonebot/kaa/sprites/{8cd02d5b-96f7-4b59-8676-ca07a63a7693.png → 720cfc0e-74a2-4239-bc08-ea9927871cd0.png} +0 -0
- /kotonebot/kaa/sprites/{74423820-b24e-4dd1-b6c4-7ef3d6aa3b8c.png → 73eec0a3-e3ba-40c8-b163-321a5b7feb81.png} +0 -0
- /kotonebot/kaa/sprites/{44d9cfe6-742c-46de-8f53-4f49babfabcc.png → 74c8b69c-bceb-438f-a4a4-49e3abd7fa46.png} +0 -0
- /kotonebot/kaa/sprites/{cde81597-2e0a-4795-910a-6e475d7cc073.png → 757d08d7-c7a1-430a-8938-edd824ed7117.png} +0 -0
- /kotonebot/kaa/sprites/{19060076-f971-411c-9b1b-f22e18871b74.png → 7e00779b-de42-4406-88f9-07d93e47f104.png} +0 -0
- /kotonebot/kaa/sprites/{9cc5a374-ca08-4fa9-a2b7-e1f65871962d.png → 82eab6fc-1968-42a4-bb43-d9cee984b33d.png} +0 -0
- /kotonebot/kaa/sprites/{74d02db5-a02d-43d0-ae7a-5aeba90249be.png → 850d5405-2103-4a2f-9e00-d5c5f43ce9a7.png} +0 -0
- /kotonebot/kaa/sprites/{9552c822-a654-46a8-acd9-0320a4b6118b.png → 864b57b0-c2f9-49eb-864c-314f72c0f56c.png} +0 -0
- /kotonebot/kaa/sprites/{92d4209d-5053-4284-a9f5-63372c8cd05b.png → 88476c65-0056-4ae4-9c9e-3ff1bae964e8.png} +0 -0
- /kotonebot/kaa/sprites/{8fc97425-3b86-42cd-820d-2ad6321508f3.png → 896ed7b5-72c8-4c1d-90ff-eb7f12876f9c.png} +0 -0
- /kotonebot/kaa/sprites/{2d59f524-840a-445f-b432-c97051eb7043.png → 8e021860-0c8f-4da5-84f8-1ed65ad6f720.png} +0 -0
- /kotonebot/kaa/sprites/{9a3c04af-7ba4-4520-a666-3045c1b3385c.png → 8e90dc5b-d79a-4133-b722-edbb14f5f0db.png} +0 -0
- /kotonebot/kaa/sprites/{180b211b-3b77-43a9-b550-6624f1b1beb1.png → 917be8d3-602c-495c-b2ed-41b1c84e7398.png} +0 -0
- /kotonebot/kaa/sprites/{5b94cf27-4aa0-4de1-a9f2-ba8f5ca790fd.png → 918db28b-0d43-4056-a506-3279f2b724c8.png} +0 -0
- /kotonebot/kaa/sprites/{5f1e618b-a1fc-41c6-9b05-f2a76c38feb5.png → 93f74a70-acd1-4453-8254-07a797839b5f.png} +0 -0
- /kotonebot/kaa/sprites/{9acad6e8-8380-47c9-bac8-3144c9b7b765.png → 99967c02-b5cf-43ba-9ca6-23e2781b25d9.png} +0 -0
- /kotonebot/kaa/sprites/{d1b23182-244c-4e94-ac46-894b3117d1bb.png → 9aee770e-1746-4076-b3c4-5da218321614.png} +0 -0
- /kotonebot/kaa/sprites/{6770f2b1-1619-4937-bf8d-284b90a5d3c6.png → 9bc1e849-e69d-4849-a849-45ea81829567.png} +0 -0
- /kotonebot/kaa/sprites/{343d630f-375f-496a-98c5-75a1e0aa2c2c.png → 9dfde42d-fd40-435b-8a41-50be0fb8781e.png} +0 -0
- /kotonebot/kaa/sprites/{cd1f5c42-582e-408e-bb9f-08f7b868d9fc.png → 9ec515d0-c177-43fa-bbf3-ea2a57080969.png} +0 -0
- /kotonebot/kaa/sprites/{9dc6ec60-597c-4305-b251-2e3342603446.png → a0fc1501-162d-49c6-824c-03e028d8fed7.png} +0 -0
- /kotonebot/kaa/sprites/{ddc4b13a-4a0f-46fd-8fcb-01100058f78a.png → a2e9d3a5-6f6f-4530-8a35-a09edfd35b8e.png} +0 -0
- /kotonebot/kaa/sprites/{76e3c1b4-cd2f-47f1-96bf-9b86a84aa24c.png → a5e11b99-d89e-47a2-ae67-4e0a04bfc022.png} +0 -0
- /kotonebot/kaa/sprites/{c447f3cf-05b3-413d-9a50-f09a22b17e8d.png → a6a23fad-cc30-43cd-b869-d2fad70d32ab.png} +0 -0
- /kotonebot/kaa/sprites/{bde3bbca-be39-494f-944a-f73582cd5f97.png → a7cc8346-8b35-4f6a-acef-8cd4d29b5591.png} +0 -0
- /kotonebot/kaa/sprites/{ee191a7a-ed3e-46e2-a07a-2ca7d566d0f6.png → a7f49544-2aaf-4f5c-a217-7203bfa87758.png} +0 -0
- /kotonebot/kaa/sprites/{01e8e85e-056c-4428-9cb2-4024c4e6d022.png → a885914f-a305-4af3-b2a5-991fdf0101f6.png} +0 -0
- /kotonebot/kaa/sprites/{6006a923-8f9b-4dfc-aa81-1e4672db6908.png → a914c9d7-3a19-4d9c-940e-579bf3f7fa79.png} +0 -0
- /kotonebot/kaa/sprites/{c673c1f3-2ac5-4fef-a9a2-203e67e1fd10.png → a9e30963-0772-401a-85f8-33369ca22267.png} +0 -0
- /kotonebot/kaa/sprites/{ab52b70e-ca1f-47fe-aff8-0bfae7eeb8ff.png → aa55089d-7b80-4763-a226-cde10e56f8a5.png} +0 -0
- /kotonebot/kaa/sprites/{3ac2cb20-6563-4505-85bc-1fd3b93902a3.png → aed0fd9a-0e59-4ead-b6a2-497b94f0eb16.png} +0 -0
- /kotonebot/kaa/sprites/{f2b30fe6-1a32-4f0f-98c1-478e90db1f1b.png → af5714a6-e4a0-47ef-9151-2a8c9614e931.png} +0 -0
- /kotonebot/kaa/sprites/{70a0da32-7fe7-41a9-9fc1-265764a0b125.png → b176f60c-94ba-46e3-b562-7fc86b25c17f.png} +0 -0
- /kotonebot/kaa/sprites/{d76bed23-33cf-4f86-bb01-add1185098a1.png → b22260e3-22c6-4c80-b986-f4fd8db22ddc.png} +0 -0
- /kotonebot/kaa/sprites/{d7c2d507-640e-4705-92d0-d2e3951cc29b.png → b3debf96-a90b-4de7-b19e-83c2d82075ee.png} +0 -0
- /kotonebot/kaa/sprites/{96b9b3cb-7131-46ba-a193-f46446f72194.png → b3e5704b-63c9-4226-9e49-69c680627b61.png} +0 -0
- /kotonebot/kaa/sprites/{3fa41725-c619-4ed8-811c-c6f0e9366126.png → b66ed448-356e-44f9-ad45-40473d47ee24.png} +0 -0
- /kotonebot/kaa/sprites/{d6182579-dc5d-4db9-a8be-0a7f3998abde.png → b7283194-0e6d-4ac1-84e0-c2062af8eba8.png} +0 -0
- /kotonebot/kaa/sprites/{203dfb12-640e-4437-9040-47045c9b8cbd.png → bd5190da-d3ed-462e-a573-b8f015cdef97.png} +0 -0
- /kotonebot/kaa/sprites/{d3a1c862-8f02-4aca-8b58-bbd337ab48bf.png → be0bca2e-dfd5-48b6-a2ac-e2699991d37b.png} +0 -0
- /kotonebot/kaa/sprites/{c2d305cc-8fb4-4f34-a9b3-96862837a36b.png → be2d7e60-56d2-4891-aae9-b5d2a65a8d03.png} +0 -0
- /kotonebot/kaa/sprites/{cfd353f0-073f-462e-928b-3cda9344eec4.png → c654428b-4f16-4257-800f-da627ddb7595.png} +0 -0
- /kotonebot/kaa/sprites/{58f1212f-a307-4179-a55c-8449e237cb3d.png → ca850faa-154e-4170-9446-91dd325e14af.png} +0 -0
- /kotonebot/kaa/sprites/{a5a16fb6-5513-4e17-b871-968425bfdf81.png → cce54a7c-bdd5-4063-8a40-e01709e69893.png} +0 -0
- /kotonebot/kaa/sprites/{ab39be69-bf52-4250-8e38-25b04d1e6a87.png → cd5ba3a7-96aa-4efc-97fc-b72f72d084d2.png} +0 -0
- /kotonebot/kaa/sprites/{b7ee5425-c4ec-4030-9343-1737628b1936.png → d3c31276-8395-4aa3-ae1a-4c50a24e8574.png} +0 -0
- /kotonebot/kaa/sprites/{aec4ecf4-c1d7-424f-8acc-388ff286a360.png → d40a6e09-4740-41a8-af0f-9da09de38bf1.png} +0 -0
- /kotonebot/kaa/sprites/{b28eac50-4517-4fc3-8fd9-a6a7f8d19ba5.png → d559328f-9b26-4ea1-8f96-f432abf0214d.png} +0 -0
- /kotonebot/kaa/sprites/{876ec159-fc25-4c97-9c37-e3ffaba7618b.png → d597a32e-5ccb-4550-ab18-1905123c22d4.png} +0 -0
- /kotonebot/kaa/sprites/{248f9401-c340-474f-baed-1a523f441f3e.png → d5a25a5f-8bd0-4f09-aec7-fda24eaf795e.png} +0 -0
- /kotonebot/kaa/sprites/{8fb0f6d1-388b-41b3-964b-5965c58605c7.png → d9432d63-1aef-43a7-8642-d10f3c15b092.png} +0 -0
- /kotonebot/kaa/sprites/{52e0b7fe-271f-4713-b1b3-b06a286630d7.png → da351a32-c51f-4746-8f89-778343772d08.png} +0 -0
- /kotonebot/kaa/sprites/{77c9d69b-1078-477f-897f-c50bc5013fd5.png → da7ef120-103c-4d5f-b95c-2bcd29757d3c.png} +0 -0
- /kotonebot/kaa/sprites/{ef8b7148-cc8f-4a76-a981-68062909e5a9.png → e4c40e7a-f67c-45d6-9775-8389bcff0b67.png} +0 -0
- /kotonebot/kaa/sprites/{9cf406dc-bd69-4919-a396-d7e267b01645.png → e850b360-da95-4498-ab3e-177e0d57e189.png} +0 -0
- /kotonebot/kaa/sprites/{63a3a9ca-aff2-428a-8df2-9a0ed4e398c6.png → e8935f50-3109-4d98-9783-86738763a431.png} +0 -0
- /kotonebot/kaa/sprites/{190c0a4a-24c2-4717-8a78-ffa7bb0366d2.png → ed2f8cd2-be82-4d48-acd0-c48cf8bdd800.png} +0 -0
- /kotonebot/kaa/sprites/{39a5eb7d-0ece-4eca-bf0e-4bf2f8faf1e2.png → ed56bfc1-d3c5-4bc3-a910-f861cfb2f379.png} +0 -0
- /kotonebot/kaa/sprites/{065cbac0-e09a-4bec-aa10-5fdb41720d31.png → ed822aca-dde6-4235-8776-0c47884c4a9a.png} +0 -0
- /kotonebot/kaa/sprites/{c2841576-352b-41de-95d8-3f2640504c9c.png → ef46ae80-8c34-4948-9076-b0536805e7dc.png} +0 -0
- /kotonebot/kaa/sprites/{9f8332c7-95b4-41ec-8e7f-f5ece0a545e1.png → f11ca963-fc05-4486-acf7-aa8f7415e6b5.png} +0 -0
- /kotonebot/kaa/sprites/{c44a35b8-4254-4f4f-99a8-18a3195ae696.png → f404eabd-6b87-48a4-8ad7-1e7d521daa94.png} +0 -0
- /kotonebot/kaa/sprites/{c14e3dd6-ffca-4011-b24d-da330162804d.png → f61e28cd-9eaa-4d3c-b25d-8bfdaecb1255.png} +0 -0
- /kotonebot/kaa/sprites/{929d1dc7-6f9e-444b-9b57-ab8baacfe524.png → f9bba6f1-6237-43bf-85b1-f6250a64a5d6.png} +0 -0
- /kotonebot/kaa/sprites/{327733fe-e68a-4f96-9e42-2b16629cbf8a.png → fb2694c2-8f0e-4ec3-9d76-087f085f2e55.png} +0 -0
- /kotonebot/kaa/sprites/{58cbe76f-7cab-490d-8668-1076e76d9e9f.png → fbe45406-81bd-4298-ab4f-ed7346c25eb8.png} +0 -0
- {ksaa-2025.8.2.0.dist-info → ksaa-2025.8.17.0.dist-info}/WHEEL +0 -0
- {ksaa-2025.8.2.0.dist-info → ksaa-2025.8.17.0.dist-info}/entry_points.txt +0 -0
- {ksaa-2025.8.2.0.dist-info → ksaa-2025.8.17.0.dist-info}/licenses/LICENSE +0 -0
- {ksaa-2025.8.2.0.dist-info → ksaa-2025.8.17.0.dist-info}/top_level.txt +0 -0
kotonebot/backend/loop.py
CHANGED
|
@@ -1,277 +1,277 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from functools import lru_cache, partial
|
|
3
|
-
from typing import Callable, Any, overload, Literal, Generic, TypeVar, cast, get_args, get_origin
|
|
4
|
-
|
|
5
|
-
from cv2.typing import MatLike
|
|
6
|
-
|
|
7
|
-
from kotonebot.util import Interval
|
|
8
|
-
from kotonebot import device, image, ocr
|
|
9
|
-
from kotonebot.backend.core import Image
|
|
10
|
-
from kotonebot.backend.ocr import TextComparator
|
|
11
|
-
from kotonebot.client.protocol import ClickableObjectProtocol
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class LoopAction:
|
|
15
|
-
def __init__(self, loop: 'Loop', func: Callable[[], ClickableObjectProtocol | None]):
|
|
16
|
-
self.loop = loop
|
|
17
|
-
self.func = func
|
|
18
|
-
self.result: ClickableObjectProtocol | None = None
|
|
19
|
-
|
|
20
|
-
@property
|
|
21
|
-
def found(self):
|
|
22
|
-
"""
|
|
23
|
-
是否找到结果。若父 Loop 未在运行中,则返回 False。
|
|
24
|
-
"""
|
|
25
|
-
if not self.loop.running:
|
|
26
|
-
return False
|
|
27
|
-
return bool(self.result)
|
|
28
|
-
|
|
29
|
-
def __bool__(self):
|
|
30
|
-
return self.found
|
|
31
|
-
|
|
32
|
-
def reset(self):
|
|
33
|
-
"""
|
|
34
|
-
重置 LoopAction,以复用此对象。
|
|
35
|
-
"""
|
|
36
|
-
self.result = None
|
|
37
|
-
|
|
38
|
-
def do(self):
|
|
39
|
-
"""
|
|
40
|
-
执行 LoopAction。
|
|
41
|
-
:return: 执行结果。
|
|
42
|
-
"""
|
|
43
|
-
if not self.loop.running:
|
|
44
|
-
return
|
|
45
|
-
if self.loop.found_anything:
|
|
46
|
-
# 本轮循环已执行任意操作,因此不需要再继续检测
|
|
47
|
-
return
|
|
48
|
-
self.result = self.func()
|
|
49
|
-
if self.result:
|
|
50
|
-
self.loop.found_anything = True
|
|
51
|
-
|
|
52
|
-
def click(self, *, at: tuple[int, int] | None = None):
|
|
53
|
-
"""
|
|
54
|
-
点击寻找结果。若结果为空,会跳过执行。
|
|
55
|
-
|
|
56
|
-
:return:
|
|
57
|
-
"""
|
|
58
|
-
if self.result:
|
|
59
|
-
if at is not None:
|
|
60
|
-
device.click(*at)
|
|
61
|
-
else:
|
|
62
|
-
device.click(self.result)
|
|
63
|
-
|
|
64
|
-
def call(self, func: Callable[[ClickableObjectProtocol], Any]):
|
|
65
|
-
pass
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class Loop:
|
|
69
|
-
def __init__(
|
|
70
|
-
self,
|
|
71
|
-
*,
|
|
72
|
-
timeout: float = 300,
|
|
73
|
-
interval: float = 0.3,
|
|
74
|
-
auto_screenshot: bool = True
|
|
75
|
-
):
|
|
76
|
-
self.running = True
|
|
77
|
-
self.found_anything = False
|
|
78
|
-
self.auto_screenshot = auto_screenshot
|
|
79
|
-
"""
|
|
80
|
-
是否在每次循环开始时(Loop.tick() 被调用时)截图。
|
|
81
|
-
"""
|
|
82
|
-
self.__last_loop: float = -1
|
|
83
|
-
self.__interval = Interval(interval)
|
|
84
|
-
self.screenshot: MatLike | None = None
|
|
85
|
-
"""上次截图时的图像数据。"""
|
|
86
|
-
|
|
87
|
-
def __iter__(self):
|
|
88
|
-
self.__interval.reset()
|
|
89
|
-
return self
|
|
90
|
-
|
|
91
|
-
def __next__(self):
|
|
92
|
-
if not self.running:
|
|
93
|
-
raise StopIteration
|
|
94
|
-
self.found_anything = False
|
|
95
|
-
self.__last_loop = time.time()
|
|
96
|
-
return self.tick()
|
|
97
|
-
|
|
98
|
-
def tick(self):
|
|
99
|
-
self.__interval.wait()
|
|
100
|
-
if self.auto_screenshot:
|
|
101
|
-
self.screenshot = device.screenshot()
|
|
102
|
-
self.__last_loop = time.time()
|
|
103
|
-
self.found_anything = False
|
|
104
|
-
return self
|
|
105
|
-
|
|
106
|
-
def exit(self):
|
|
107
|
-
"""
|
|
108
|
-
结束循环。
|
|
109
|
-
"""
|
|
110
|
-
self.running = False
|
|
111
|
-
|
|
112
|
-
@overload
|
|
113
|
-
def when(self, condition: Image) -> LoopAction:
|
|
114
|
-
...
|
|
115
|
-
|
|
116
|
-
@overload
|
|
117
|
-
def when(self, condition: TextComparator) -> LoopAction:
|
|
118
|
-
...
|
|
119
|
-
|
|
120
|
-
def when(self, condition: Any):
|
|
121
|
-
"""
|
|
122
|
-
判断某个条件是否成立。
|
|
123
|
-
|
|
124
|
-
:param condition:
|
|
125
|
-
:return:
|
|
126
|
-
"""
|
|
127
|
-
if isinstance(condition, Image):
|
|
128
|
-
func = partial(image.find, condition)
|
|
129
|
-
elif isinstance(condition, TextComparator):
|
|
130
|
-
func = partial(ocr.find, condition)
|
|
131
|
-
else:
|
|
132
|
-
raise ValueError('Invalid condition type.')
|
|
133
|
-
la = LoopAction(self, func)
|
|
134
|
-
la.reset()
|
|
135
|
-
la.do()
|
|
136
|
-
return la
|
|
137
|
-
|
|
138
|
-
def until(self, condition: Any):
|
|
139
|
-
"""
|
|
140
|
-
当满足指定条件时,结束循环。
|
|
141
|
-
|
|
142
|
-
等价于 ``loop.when(...).call(lambda _: loop.exit())``
|
|
143
|
-
"""
|
|
144
|
-
return self.when(condition).call(lambda _: self.exit())
|
|
145
|
-
|
|
146
|
-
def click_if(self, condition: Any, *, at: tuple[int, int] | None = None):
|
|
147
|
-
"""
|
|
148
|
-
检测指定对象是否出现,若出现,点击该对象或指定位置。
|
|
149
|
-
|
|
150
|
-
``click_if()`` 等价于 ``loop.when(...).click(...)``。
|
|
151
|
-
|
|
152
|
-
:param condition: 检测目标。
|
|
153
|
-
:param at: 点击位置。若为 None,表示点击找到的目标。
|
|
154
|
-
"""
|
|
155
|
-
return self.when(condition).click(at=at)
|
|
156
|
-
|
|
157
|
-
StateType = TypeVar('StateType')
|
|
158
|
-
class StatedLoop(Loop, Generic[StateType]):
|
|
159
|
-
def __init__(
|
|
160
|
-
self,
|
|
161
|
-
states: list[Any] | None = None,
|
|
162
|
-
initial_state: StateType | None = None,
|
|
163
|
-
*,
|
|
164
|
-
timeout: float = 300,
|
|
165
|
-
interval: float = 0.3,
|
|
166
|
-
auto_screenshot: bool = True
|
|
167
|
-
):
|
|
168
|
-
self.__tmp_states = states
|
|
169
|
-
self.__tmp_initial_state = initial_state
|
|
170
|
-
self.state: StateType
|
|
171
|
-
super().__init__(timeout=timeout, interval=interval, auto_screenshot=auto_screenshot)
|
|
172
|
-
|
|
173
|
-
def __iter__(self):
|
|
174
|
-
# __retrive_state_values() 只能在非 __init__ 中调用
|
|
175
|
-
self.__retrive_state_values()
|
|
176
|
-
return super().__iter__()
|
|
177
|
-
|
|
178
|
-
def __retrive_state_values(self):
|
|
179
|
-
# HACK: __orig_class__ 是 undocumented 属性
|
|
180
|
-
if not hasattr(self, '__orig_class__'):
|
|
181
|
-
# 如果 Foo 不是以参数化泛型的方式实例化的,可能没有 __orig_class__
|
|
182
|
-
if self.state is None:
|
|
183
|
-
raise ValueError('Either specify `states` or use StatedLoop[Literal[...]] syntax.')
|
|
184
|
-
else:
|
|
185
|
-
generic_type_args = get_args(self.__orig_class__) # type: ignore
|
|
186
|
-
if len(generic_type_args) != 1:
|
|
187
|
-
raise ValueError('StatedLoop must have exactly one generic type argument.')
|
|
188
|
-
state_values = get_args(generic_type_args[0])
|
|
189
|
-
if not state_values:
|
|
190
|
-
raise ValueError('StatedLoop must have at least one state value.')
|
|
191
|
-
self.states = cast(tuple[StateType, ...], state_values)
|
|
192
|
-
self.state = self.__tmp_initial_state or self.states[0]
|
|
193
|
-
return state_values
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def StatedLoop2(states: StateType) -> StatedLoop[StateType]:
|
|
197
|
-
state_values = get_args(states)
|
|
198
|
-
return cast(StatedLoop[StateType], Loop())
|
|
199
|
-
|
|
200
|
-
if __name__ == '__main__':
|
|
201
|
-
from kotonebot.kaa.tasks import R
|
|
202
|
-
from kotonebot.backend.ocr import contains
|
|
203
|
-
from kotonebot.backend.context import manual_context, init_context
|
|
204
|
-
|
|
205
|
-
# T = TypeVar('T')
|
|
206
|
-
# class Foo(Generic[T]):
|
|
207
|
-
# def get_literal_params(self) -> list | None:
|
|
208
|
-
# """
|
|
209
|
-
# 尝试获取泛型参数 T (如果它是 Literal 类型) 的参数列表。
|
|
210
|
-
# """
|
|
211
|
-
# # self.__orig_class__ 会是 Foo 的具体参数化类型,
|
|
212
|
-
# # 例如 Foo[Literal['p0', 'p1', 'p2', 'p3', 'ap']]
|
|
213
|
-
# if not hasattr(self, '__orig_class__'):
|
|
214
|
-
# # 如果 Foo 不是以参数化泛型的方式实例化的,可能没有 __orig_class__
|
|
215
|
-
# return None
|
|
216
|
-
#
|
|
217
|
-
# # generic_type_args 是传递给 Foo 的类型参数元组
|
|
218
|
-
# # 例如 (Literal['p0', 'p1', 'p2', 'p3', 'ap'],)
|
|
219
|
-
# generic_type_args = get_args(self.__orig_class__)
|
|
220
|
-
#
|
|
221
|
-
# if not generic_type_args:
|
|
222
|
-
# # Foo 没有类型参数
|
|
223
|
-
# return None
|
|
224
|
-
#
|
|
225
|
-
# # T_type 是 Foo 的第一个类型参数
|
|
226
|
-
# # 例如 Literal['p0', 'p1', 'p2', 'p3', 'ap']
|
|
227
|
-
# t_type = generic_type_args[0]
|
|
228
|
-
#
|
|
229
|
-
# # 检查 T_type 是否是 Literal 类型
|
|
230
|
-
# if get_origin(t_type) is Literal:
|
|
231
|
-
# # literal_args 是 Literal 类型的参数元组
|
|
232
|
-
# # 例如 ('p0', 'p1', 'p2', 'p3', 'ap')
|
|
233
|
-
# literal_args = get_args(t_type)
|
|
234
|
-
# return list(literal_args)
|
|
235
|
-
# else:
|
|
236
|
-
# # T 不是 Literal 类型
|
|
237
|
-
# return None
|
|
238
|
-
# f = Foo[Literal['p0', 'p1', 'p2', 'p3', 'ap']]()
|
|
239
|
-
# values = f.get_literal_params()
|
|
240
|
-
# 1
|
|
241
|
-
|
|
242
|
-
from typing_extensions import reveal_type
|
|
243
|
-
slp = StatedLoop[Literal['p0', 'p1', 'p2', 'p3', 'ap']]()
|
|
244
|
-
for l in slp:
|
|
245
|
-
reveal_type(l.states)
|
|
246
|
-
|
|
247
|
-
# init_context()
|
|
248
|
-
# manual_context().begin()
|
|
249
|
-
# for l in Loop():
|
|
250
|
-
# l.when(R.Produce.ButtonUse).click()
|
|
251
|
-
# l.when(R.Produce.ButtonRefillAP).click()
|
|
252
|
-
# l.when(contains("123")).click()
|
|
253
|
-
# l.click_if(contains("!23"), at=(1, 2))
|
|
254
|
-
|
|
255
|
-
# State = Literal['p0', 'p1', 'p2', 'p3', 'ap']
|
|
256
|
-
# for sl in StatedLoop[State]():
|
|
257
|
-
# match sl.state:
|
|
258
|
-
# case 'p0':
|
|
259
|
-
# sl.click_if(R.Produce.ButtonProduce)
|
|
260
|
-
# sl.click_if(contains('master'))
|
|
261
|
-
# sl.when(R.Produce.ButtonPIdolOverview).goto('p1')
|
|
262
|
-
# # AP 不足
|
|
263
|
-
# sl.when(R.Produce.TextAPInsufficient).goto('ap')
|
|
264
|
-
# case 'ap':
|
|
265
|
-
# pass
|
|
266
|
-
# # p1: 选择偶像
|
|
267
|
-
# case 'p1':
|
|
268
|
-
# sl.call(lambda _: select_idol(idol_skin_id), once=True)
|
|
269
|
-
# sl.when(R.Produce.TextAnotherIdolAvailableDialog).call(dialog.no)
|
|
270
|
-
# sl.click_if(R.Common.ButtonNextNoIcon)
|
|
271
|
-
# sl.until(R.Produce.TextStepIndicator2).goto('p2')
|
|
272
|
-
# case 'p2':
|
|
273
|
-
# sl.when(contains("123")).click()
|
|
274
|
-
# case 'p3':
|
|
275
|
-
# sl.click_if(contains("!23"), at=(1, 2))
|
|
276
|
-
# case _:
|
|
1
|
+
import time
|
|
2
|
+
from functools import lru_cache, partial
|
|
3
|
+
from typing import Callable, Any, overload, Literal, Generic, TypeVar, cast, get_args, get_origin
|
|
4
|
+
|
|
5
|
+
from cv2.typing import MatLike
|
|
6
|
+
|
|
7
|
+
from kotonebot.util import Interval
|
|
8
|
+
from kotonebot import device, image, ocr
|
|
9
|
+
from kotonebot.backend.core import Image
|
|
10
|
+
from kotonebot.backend.ocr import TextComparator
|
|
11
|
+
from kotonebot.client.protocol import ClickableObjectProtocol
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LoopAction:
|
|
15
|
+
def __init__(self, loop: 'Loop', func: Callable[[], ClickableObjectProtocol | None]):
|
|
16
|
+
self.loop = loop
|
|
17
|
+
self.func = func
|
|
18
|
+
self.result: ClickableObjectProtocol | None = None
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def found(self):
|
|
22
|
+
"""
|
|
23
|
+
是否找到结果。若父 Loop 未在运行中,则返回 False。
|
|
24
|
+
"""
|
|
25
|
+
if not self.loop.running:
|
|
26
|
+
return False
|
|
27
|
+
return bool(self.result)
|
|
28
|
+
|
|
29
|
+
def __bool__(self):
|
|
30
|
+
return self.found
|
|
31
|
+
|
|
32
|
+
def reset(self):
|
|
33
|
+
"""
|
|
34
|
+
重置 LoopAction,以复用此对象。
|
|
35
|
+
"""
|
|
36
|
+
self.result = None
|
|
37
|
+
|
|
38
|
+
def do(self):
|
|
39
|
+
"""
|
|
40
|
+
执行 LoopAction。
|
|
41
|
+
:return: 执行结果。
|
|
42
|
+
"""
|
|
43
|
+
if not self.loop.running:
|
|
44
|
+
return
|
|
45
|
+
if self.loop.found_anything:
|
|
46
|
+
# 本轮循环已执行任意操作,因此不需要再继续检测
|
|
47
|
+
return
|
|
48
|
+
self.result = self.func()
|
|
49
|
+
if self.result:
|
|
50
|
+
self.loop.found_anything = True
|
|
51
|
+
|
|
52
|
+
def click(self, *, at: tuple[int, int] | None = None):
|
|
53
|
+
"""
|
|
54
|
+
点击寻找结果。若结果为空,会跳过执行。
|
|
55
|
+
|
|
56
|
+
:return:
|
|
57
|
+
"""
|
|
58
|
+
if self.result:
|
|
59
|
+
if at is not None:
|
|
60
|
+
device.click(*at)
|
|
61
|
+
else:
|
|
62
|
+
device.click(self.result)
|
|
63
|
+
|
|
64
|
+
def call(self, func: Callable[[ClickableObjectProtocol], Any]):
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Loop:
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
*,
|
|
72
|
+
timeout: float = 300,
|
|
73
|
+
interval: float = 0.3,
|
|
74
|
+
auto_screenshot: bool = True
|
|
75
|
+
):
|
|
76
|
+
self.running = True
|
|
77
|
+
self.found_anything = False
|
|
78
|
+
self.auto_screenshot = auto_screenshot
|
|
79
|
+
"""
|
|
80
|
+
是否在每次循环开始时(Loop.tick() 被调用时)截图。
|
|
81
|
+
"""
|
|
82
|
+
self.__last_loop: float = -1
|
|
83
|
+
self.__interval = Interval(interval)
|
|
84
|
+
self.screenshot: MatLike | None = None
|
|
85
|
+
"""上次截图时的图像数据。"""
|
|
86
|
+
|
|
87
|
+
def __iter__(self):
|
|
88
|
+
self.__interval.reset()
|
|
89
|
+
return self
|
|
90
|
+
|
|
91
|
+
def __next__(self):
|
|
92
|
+
if not self.running:
|
|
93
|
+
raise StopIteration
|
|
94
|
+
self.found_anything = False
|
|
95
|
+
self.__last_loop = time.time()
|
|
96
|
+
return self.tick()
|
|
97
|
+
|
|
98
|
+
def tick(self):
|
|
99
|
+
self.__interval.wait()
|
|
100
|
+
if self.auto_screenshot:
|
|
101
|
+
self.screenshot = device.screenshot()
|
|
102
|
+
self.__last_loop = time.time()
|
|
103
|
+
self.found_anything = False
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
def exit(self):
|
|
107
|
+
"""
|
|
108
|
+
结束循环。
|
|
109
|
+
"""
|
|
110
|
+
self.running = False
|
|
111
|
+
|
|
112
|
+
@overload
|
|
113
|
+
def when(self, condition: Image) -> LoopAction:
|
|
114
|
+
...
|
|
115
|
+
|
|
116
|
+
@overload
|
|
117
|
+
def when(self, condition: TextComparator) -> LoopAction:
|
|
118
|
+
...
|
|
119
|
+
|
|
120
|
+
def when(self, condition: Any):
|
|
121
|
+
"""
|
|
122
|
+
判断某个条件是否成立。
|
|
123
|
+
|
|
124
|
+
:param condition:
|
|
125
|
+
:return:
|
|
126
|
+
"""
|
|
127
|
+
if isinstance(condition, Image):
|
|
128
|
+
func = partial(image.find, condition)
|
|
129
|
+
elif isinstance(condition, TextComparator):
|
|
130
|
+
func = partial(ocr.find, condition)
|
|
131
|
+
else:
|
|
132
|
+
raise ValueError('Invalid condition type.')
|
|
133
|
+
la = LoopAction(self, func)
|
|
134
|
+
la.reset()
|
|
135
|
+
la.do()
|
|
136
|
+
return la
|
|
137
|
+
|
|
138
|
+
def until(self, condition: Any):
|
|
139
|
+
"""
|
|
140
|
+
当满足指定条件时,结束循环。
|
|
141
|
+
|
|
142
|
+
等价于 ``loop.when(...).call(lambda _: loop.exit())``
|
|
143
|
+
"""
|
|
144
|
+
return self.when(condition).call(lambda _: self.exit())
|
|
145
|
+
|
|
146
|
+
def click_if(self, condition: Any, *, at: tuple[int, int] | None = None):
|
|
147
|
+
"""
|
|
148
|
+
检测指定对象是否出现,若出现,点击该对象或指定位置。
|
|
149
|
+
|
|
150
|
+
``click_if()`` 等价于 ``loop.when(...).click(...)``。
|
|
151
|
+
|
|
152
|
+
:param condition: 检测目标。
|
|
153
|
+
:param at: 点击位置。若为 None,表示点击找到的目标。
|
|
154
|
+
"""
|
|
155
|
+
return self.when(condition).click(at=at)
|
|
156
|
+
|
|
157
|
+
StateType = TypeVar('StateType')
|
|
158
|
+
class StatedLoop(Loop, Generic[StateType]):
|
|
159
|
+
def __init__(
|
|
160
|
+
self,
|
|
161
|
+
states: list[Any] | None = None,
|
|
162
|
+
initial_state: StateType | None = None,
|
|
163
|
+
*,
|
|
164
|
+
timeout: float = 300,
|
|
165
|
+
interval: float = 0.3,
|
|
166
|
+
auto_screenshot: bool = True
|
|
167
|
+
):
|
|
168
|
+
self.__tmp_states = states
|
|
169
|
+
self.__tmp_initial_state = initial_state
|
|
170
|
+
self.state: StateType
|
|
171
|
+
super().__init__(timeout=timeout, interval=interval, auto_screenshot=auto_screenshot)
|
|
172
|
+
|
|
173
|
+
def __iter__(self):
|
|
174
|
+
# __retrive_state_values() 只能在非 __init__ 中调用
|
|
175
|
+
self.__retrive_state_values()
|
|
176
|
+
return super().__iter__()
|
|
177
|
+
|
|
178
|
+
def __retrive_state_values(self):
|
|
179
|
+
# HACK: __orig_class__ 是 undocumented 属性
|
|
180
|
+
if not hasattr(self, '__orig_class__'):
|
|
181
|
+
# 如果 Foo 不是以参数化泛型的方式实例化的,可能没有 __orig_class__
|
|
182
|
+
if self.state is None:
|
|
183
|
+
raise ValueError('Either specify `states` or use StatedLoop[Literal[...]] syntax.')
|
|
184
|
+
else:
|
|
185
|
+
generic_type_args = get_args(self.__orig_class__) # type: ignore
|
|
186
|
+
if len(generic_type_args) != 1:
|
|
187
|
+
raise ValueError('StatedLoop must have exactly one generic type argument.')
|
|
188
|
+
state_values = get_args(generic_type_args[0])
|
|
189
|
+
if not state_values:
|
|
190
|
+
raise ValueError('StatedLoop must have at least one state value.')
|
|
191
|
+
self.states = cast(tuple[StateType, ...], state_values)
|
|
192
|
+
self.state = self.__tmp_initial_state or self.states[0]
|
|
193
|
+
return state_values
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def StatedLoop2(states: StateType) -> StatedLoop[StateType]:
|
|
197
|
+
state_values = get_args(states)
|
|
198
|
+
return cast(StatedLoop[StateType], Loop())
|
|
199
|
+
|
|
200
|
+
if __name__ == '__main__':
|
|
201
|
+
from kotonebot.kaa.tasks import R
|
|
202
|
+
from kotonebot.backend.ocr import contains
|
|
203
|
+
from kotonebot.backend.context import manual_context, init_context
|
|
204
|
+
|
|
205
|
+
# T = TypeVar('T')
|
|
206
|
+
# class Foo(Generic[T]):
|
|
207
|
+
# def get_literal_params(self) -> list | None:
|
|
208
|
+
# """
|
|
209
|
+
# 尝试获取泛型参数 T (如果它是 Literal 类型) 的参数列表。
|
|
210
|
+
# """
|
|
211
|
+
# # self.__orig_class__ 会是 Foo 的具体参数化类型,
|
|
212
|
+
# # 例如 Foo[Literal['p0', 'p1', 'p2', 'p3', 'ap']]
|
|
213
|
+
# if not hasattr(self, '__orig_class__'):
|
|
214
|
+
# # 如果 Foo 不是以参数化泛型的方式实例化的,可能没有 __orig_class__
|
|
215
|
+
# return None
|
|
216
|
+
#
|
|
217
|
+
# # generic_type_args 是传递给 Foo 的类型参数元组
|
|
218
|
+
# # 例如 (Literal['p0', 'p1', 'p2', 'p3', 'ap'],)
|
|
219
|
+
# generic_type_args = get_args(self.__orig_class__)
|
|
220
|
+
#
|
|
221
|
+
# if not generic_type_args:
|
|
222
|
+
# # Foo 没有类型参数
|
|
223
|
+
# return None
|
|
224
|
+
#
|
|
225
|
+
# # T_type 是 Foo 的第一个类型参数
|
|
226
|
+
# # 例如 Literal['p0', 'p1', 'p2', 'p3', 'ap']
|
|
227
|
+
# t_type = generic_type_args[0]
|
|
228
|
+
#
|
|
229
|
+
# # 检查 T_type 是否是 Literal 类型
|
|
230
|
+
# if get_origin(t_type) is Literal:
|
|
231
|
+
# # literal_args 是 Literal 类型的参数元组
|
|
232
|
+
# # 例如 ('p0', 'p1', 'p2', 'p3', 'ap')
|
|
233
|
+
# literal_args = get_args(t_type)
|
|
234
|
+
# return list(literal_args)
|
|
235
|
+
# else:
|
|
236
|
+
# # T 不是 Literal 类型
|
|
237
|
+
# return None
|
|
238
|
+
# f = Foo[Literal['p0', 'p1', 'p2', 'p3', 'ap']]()
|
|
239
|
+
# values = f.get_literal_params()
|
|
240
|
+
# 1
|
|
241
|
+
|
|
242
|
+
from typing_extensions import reveal_type
|
|
243
|
+
slp = StatedLoop[Literal['p0', 'p1', 'p2', 'p3', 'ap']]()
|
|
244
|
+
for l in slp:
|
|
245
|
+
reveal_type(l.states)
|
|
246
|
+
|
|
247
|
+
# init_context()
|
|
248
|
+
# manual_context().begin()
|
|
249
|
+
# for l in Loop():
|
|
250
|
+
# l.when(R.Produce.ButtonUse).click()
|
|
251
|
+
# l.when(R.Produce.ButtonRefillAP).click()
|
|
252
|
+
# l.when(contains("123")).click()
|
|
253
|
+
# l.click_if(contains("!23"), at=(1, 2))
|
|
254
|
+
|
|
255
|
+
# State = Literal['p0', 'p1', 'p2', 'p3', 'ap']
|
|
256
|
+
# for sl in StatedLoop[State]():
|
|
257
|
+
# match sl.state:
|
|
258
|
+
# case 'p0':
|
|
259
|
+
# sl.click_if(R.Produce.ButtonProduce)
|
|
260
|
+
# sl.click_if(contains('master'))
|
|
261
|
+
# sl.when(R.Produce.ButtonPIdolOverview).goto('p1')
|
|
262
|
+
# # AP 不足
|
|
263
|
+
# sl.when(R.Produce.TextAPInsufficient).goto('ap')
|
|
264
|
+
# case 'ap':
|
|
265
|
+
# pass
|
|
266
|
+
# # p1: 选择偶像
|
|
267
|
+
# case 'p1':
|
|
268
|
+
# sl.call(lambda _: select_idol(idol_skin_id), once=True)
|
|
269
|
+
# sl.when(R.Produce.TextAnotherIdolAvailableDialog).call(dialog.no)
|
|
270
|
+
# sl.click_if(R.Common.ButtonNextNoIcon)
|
|
271
|
+
# sl.until(R.Produce.TextStepIndicator2).goto('p2')
|
|
272
|
+
# case 'p2':
|
|
273
|
+
# sl.when(contains("123")).click()
|
|
274
|
+
# case 'p3':
|
|
275
|
+
# sl.click_if(contains("!23"), at=(1, 2))
|
|
276
|
+
# case _:
|
|
277
277
|
# assert_never(sl.state)
|
kotonebot/kaa/main/gr.py
CHANGED
|
@@ -881,7 +881,7 @@ class KotoneBotUI:
|
|
|
881
881
|
new_value = choices[0]
|
|
882
882
|
else:
|
|
883
883
|
new_value = impl_value
|
|
884
|
-
return
|
|
884
|
+
return new_value
|
|
885
885
|
|
|
886
886
|
with gr.Tabs(selected=self.current_config.backend.type):
|
|
887
887
|
with gr.Tab("MuMu 12", id="mumu12") as tab_mumu12:
|
|
@@ -1405,12 +1405,6 @@ class KotoneBotUI:
|
|
|
1405
1405
|
info="进行一次 REGULAR 培育需要 ~30min,进行一次 PRO 培育需要 ~1h(具体视设备性能而定)。",
|
|
1406
1406
|
visible=False
|
|
1407
1407
|
)
|
|
1408
|
-
produce_count = gr.Number(
|
|
1409
|
-
minimum=1,
|
|
1410
|
-
label="培育次数",
|
|
1411
|
-
info="培育的次数。",
|
|
1412
|
-
visible=False
|
|
1413
|
-
)
|
|
1414
1408
|
|
|
1415
1409
|
# 添加偶像选择
|
|
1416
1410
|
idol_choices = []
|
|
@@ -1526,13 +1520,6 @@ class KotoneBotUI:
|
|
|
1526
1520
|
label="培育模式",
|
|
1527
1521
|
info="进行一次 REGULAR 培育需要 ~30min,进行一次 PRO 培育需要 ~1h(具体视设备性能而定)。"
|
|
1528
1522
|
)
|
|
1529
|
-
produce_count = gr.Number(
|
|
1530
|
-
minimum=1,
|
|
1531
|
-
value=self.current_config.options.produce.produce_count,
|
|
1532
|
-
label="培育次数",
|
|
1533
|
-
interactive=True,
|
|
1534
|
-
info="培育的次数。"
|
|
1535
|
-
)
|
|
1536
1523
|
|
|
1537
1524
|
# 添加偶像选择
|
|
1538
1525
|
idol_choices = []
|
|
@@ -1663,7 +1650,6 @@ class KotoneBotUI:
|
|
|
1663
1650
|
gr.Textbox(value="", visible=False), # solution_name
|
|
1664
1651
|
gr.Textbox(value="", visible=False), # solution_description
|
|
1665
1652
|
gr.Dropdown(visible=False), # produce_mode
|
|
1666
|
-
gr.Number(visible=False), # produce_count
|
|
1667
1653
|
gr.Dropdown(visible=False), # produce_idols
|
|
1668
1654
|
gr.Markdown(visible=False), # kotone_warning
|
|
1669
1655
|
gr.Checkbox(visible=False), # auto_set_memory
|
|
@@ -1693,7 +1679,6 @@ class KotoneBotUI:
|
|
|
1693
1679
|
gr.Textbox(value=solution.name, visible=True),
|
|
1694
1680
|
gr.Textbox(value=solution.description or "", visible=True),
|
|
1695
1681
|
gr.Dropdown(value=solution.data.mode, visible=True),
|
|
1696
|
-
gr.Number(value=self.current_config.options.produce.produce_count, visible=True),
|
|
1697
1682
|
gr.Dropdown(value=solution.data.idol, visible=True),
|
|
1698
1683
|
gr.Markdown(visible=has_kotone and not is_strict_mode),
|
|
1699
1684
|
gr.Checkbox(value=solution.data.auto_set_memory, visible=True),
|
|
@@ -1789,7 +1774,7 @@ class KotoneBotUI:
|
|
|
1789
1774
|
else:
|
|
1790
1775
|
return gr.Dropdown()
|
|
1791
1776
|
|
|
1792
|
-
def on_save_solution(solution_id, name, description, mode,
|
|
1777
|
+
def on_save_solution(solution_id, name, description, mode, idols, auto_memory, memory_sets,
|
|
1793
1778
|
auto_support, support_card_sets, pt_boost, note_boost, follow_producer, study_lesson, prefer_ap,
|
|
1794
1779
|
actions, detection_mode, ap_drink, skip_commu_val):
|
|
1795
1780
|
"""保存培育方案"""
|
|
@@ -1831,9 +1816,6 @@ class KotoneBotUI:
|
|
|
1831
1816
|
# 保存方案
|
|
1832
1817
|
solution_manager.save(solution_id, solution)
|
|
1833
1818
|
|
|
1834
|
-
# 同时更新配置中的 produce_count
|
|
1835
|
-
self.current_config.options.produce.produce_count = int(count)
|
|
1836
|
-
|
|
1837
1819
|
# 重新列出所有方案(确保没有重复项)
|
|
1838
1820
|
solutions = solution_manager.list()
|
|
1839
1821
|
solution_choices = [(f"{sol.name} - {sol.description or '无描述'}", sol.id) for sol in solutions]
|
|
@@ -1884,7 +1866,7 @@ class KotoneBotUI:
|
|
|
1884
1866
|
inputs=[solution_dropdown],
|
|
1885
1867
|
outputs=[
|
|
1886
1868
|
solution_name, solution_description,
|
|
1887
|
-
produce_mode,
|
|
1869
|
+
produce_mode, produce_idols, kotone_warning,
|
|
1888
1870
|
auto_set_memory, memory_sets_group, memory_sets,
|
|
1889
1871
|
auto_set_support, support_card_sets_group, support_card_sets,
|
|
1890
1872
|
use_pt_boost, use_note_boost, follow_producer,
|
|
@@ -1920,7 +1902,7 @@ class KotoneBotUI:
|
|
|
1920
1902
|
fn=on_save_solution,
|
|
1921
1903
|
inputs=[
|
|
1922
1904
|
solution_dropdown, solution_name, solution_description,
|
|
1923
|
-
produce_mode,
|
|
1905
|
+
produce_mode, produce_idols,
|
|
1924
1906
|
auto_set_memory, memory_sets, auto_set_support, support_card_sets,
|
|
1925
1907
|
use_pt_boost, use_note_boost, follow_producer,
|
|
1926
1908
|
self_study_lesson, prefer_lesson_ap, actions_order,
|
|
@@ -2305,7 +2287,7 @@ class KotoneBotUI:
|
|
|
2305
2287
|
|
|
2306
2288
|
def _create_settings_tab(self) -> None:
|
|
2307
2289
|
with gr.Tab("设置"):
|
|
2308
|
-
gr.Markdown("## 设置")
|
|
2290
|
+
gr.Markdown("## 设置 <span style='color: red; font-size: 0.8rem; font-weight: normal;'>设置修改后需要保存(网页底部)才会生效!</span>")
|
|
2309
2291
|
|
|
2310
2292
|
# 模拟器设置
|
|
2311
2293
|
emulator_settings = self._create_emulator_settings()
|
kotonebot/kaa/metadata.py
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
WHATS_NEW = """
|
|
2
2
|
# 更新日志
|
|
3
3
|
## kaa
|
|
4
|
+
### v2025.8.17.0
|
|
5
|
+
脚本:
|
|
6
|
+
* [修复] 尝试修复进入每日商店时报错的问题(#e9529b7)
|
|
7
|
+
* [修复] 修复刷新商店商品时脚本不会等待刷新完成的问题(#180d800)
|
|
8
|
+
* [修复] 修复商店刷新后第二次购买会跳过第一行的问题 #59(#a327791)
|
|
9
|
+
* [修复] 修复金币商店购买一个物品总是点击两次的问题(#94a264e)
|
|
10
|
+
|
|
11
|
+
界面:
|
|
12
|
+
* [修复] 移除模拟器设置的最后多余的 Dropdown(#91d05b1)
|
|
13
|
+
* [修复] 移除培育方案中多余的培育次数输入框(#c0549d9)
|
|
14
|
+
* [新增] 新增保存设置提示(#b56eabc)
|
|
15
|
+
|
|
4
16
|
### v2025.8.2.0
|
|
5
17
|
脚本:
|
|
6
18
|
* [修复] 修复 DMM 版启动游戏提示找不到窗口的问题(#46e72c4)
|
|
Binary file
|