ksaa 2025.7.20.0__py3-none-any.whl → 2025.7.27.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/bot.py +60 -12
- kotonebot/backend/context/task_action.py +9 -46
- kotonebot/backend/dispatch.py +1 -104
- kotonebot/backend/flow_controller.py +3 -1
- kotonebot/errors.py +37 -2
- kotonebot/interop/win/message_box.py +314 -0
- kotonebot/interop/win/task_dialog.py +469 -0
- kotonebot/kaa/config/produce.py +8 -6
- kotonebot/kaa/config/schema.py +2 -0
- kotonebot/kaa/errors.py +38 -0
- kotonebot/kaa/main/gr.py +22 -5
- kotonebot/kaa/metadata.py +14 -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/tasks/R.py +126 -126
- kotonebot/kaa/tasks/daily/contest.py +39 -8
- kotonebot/kaa/tasks/daily/purchase.py +0 -1
- kotonebot/kaa/tasks/end_game.py +4 -3
- kotonebot/kaa/tasks/produce/in_purodyuusu.py +32 -29
- kotonebot/kaa/tasks/produce/produce.py +2 -1
- kotonebot/kaa/tasks/start_game.py +2 -0
- kotonebot/ui/user.py +43 -13
- {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.0.dist-info}/METADATA +2 -1
- {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.0.dist-info}/RECORD +155 -152
- /kotonebot/kaa/sprites/{70671b9e-9ebb-4dee-bc5a-dbcb70364adf.png → 039771df-9741-4f4e-9793-9017386ac68e.png} +0 -0
- /kotonebot/kaa/sprites/{32907971-0e98-4adc-91b8-ac0308c11c3c.png → 0c826d2e-41ce-474b-ad99-f4561baf03de.png} +0 -0
- /kotonebot/kaa/sprites/{89d3c0a6-266e-486e-998d-ecd0d2536814.png → 0fb240b0-1bb5-4aee-8ad3-a24062ee9a20.png} +0 -0
- /kotonebot/kaa/sprites/{20733b9b-1df7-42af-ab55-3364e8623602.png → 10636534-51ee-4698-b582-e56751bebb4d.png} +0 -0
- /kotonebot/kaa/sprites/{562f176f-af1e-4352-aeed-62e362177f9f.png → 1218bb7e-2cab-477e-aa51-f71aa4f52a7d.png} +0 -0
- /kotonebot/kaa/sprites/{b66e13a1-636c-4478-9d72-7d200ff670a9.png → 1917a430-d216-4359-8f62-0b62108f58c1.png} +0 -0
- /kotonebot/kaa/sprites/{39f88061-a997-4a8a-b09e-4a2425f4a83a.png → 1f56fbc1-47f5-4dc3-b91b-6e49e4ea00dc.png} +0 -0
- /kotonebot/kaa/sprites/{3e613561-8dbd-4094-9889-53f08541a716.png → 25797538-2dc6-436c-b64a-597ae6d5db6e.png} +0 -0
- /kotonebot/kaa/sprites/{38c0ed08-5af3-4fca-a37f-27d66fd35a4c.png → 27d59ead-0f94-4554-8c9a-cd3aeb606fea.png} +0 -0
- /kotonebot/kaa/sprites/{cab0b1ff-b40a-42a8-b799-75e309b2dee3.png → 2822bf2b-b350-437b-b330-0e8c122bfbe7.png} +0 -0
- /kotonebot/kaa/sprites/{9169bf8e-5907-42e5-b102-47da3bf9a0b1.png → 287ec12a-c1fb-4b8f-a77c-acc99821eabd.png} +0 -0
- /kotonebot/kaa/sprites/{131fb7e1-6eb9-4722-9943-76ff05c5baee.png → 290aaff5-71eb-4d71-87db-3757d3e9794b.png} +0 -0
- /kotonebot/kaa/sprites/{1737a9e0-f8c4-416e-bbad-cb97a658ae9a.png → 29fcf4cb-883f-475e-a68f-107cffc83f1c.png} +0 -0
- /kotonebot/kaa/sprites/{6ac4a3b5-66d2-4429-8cd1-945fbb48280c.png → 2ac90dcf-2284-437e-a61e-51934f937f8f.png} +0 -0
- /kotonebot/kaa/sprites/{05a23a4a-9b93-4fbd-b4e9-15a7c4a91fdc.png → 2e3410a1-49b5-4f65-8f26-bb1df213c2b8.png} +0 -0
- /kotonebot/kaa/sprites/{9b696383-10dd-4a35-8546-1ccdb8891373.png → 30bc31e4-40b3-4bcb-bb36-1dd5a8c59a32.png} +0 -0
- /kotonebot/kaa/sprites/{9dbc5d76-8c6a-4638-b0c2-eba79542ec58.png → 34eaf943-a8b5-4358-aadc-62ff656ab542.png} +0 -0
- /kotonebot/kaa/sprites/{0aa4472c-b533-46cc-a072-9d165d955424.png → 37f1d878-467f-4ba0-bc59-bb327797191b.png} +0 -0
- /kotonebot/kaa/sprites/{1aed664e-ceb3-4a1d-a338-df08dc8ebbd3.png → 3aa13898-1a50-4234-b9ec-f35878f05592.png} +0 -0
- /kotonebot/kaa/sprites/{0e29489c-6728-46cd-bd13-2b9d9e74b2da.png → 3ca43ccf-8748-439f-80f7-a95978a6b1f2.png} +0 -0
- /kotonebot/kaa/sprites/{dcc2da94-2c9d-4248-bce5-731651e391ae.png → 3efe8341-33bc-492e-8a0f-69a507502b43.png} +0 -0
- /kotonebot/kaa/sprites/{b169172d-8ce2-432a-bed6-1dfc30bcc95c.png → 3f6b5de5-c942-4ef1-8b04-5ee6859bb27b.png} +0 -0
- /kotonebot/kaa/sprites/{f0952cb2-dadb-4d9a-933e-cabcbf8850fb.png → 432aad91-9cc5-4518-bbfd-6cbed522dac6.png} +0 -0
- /kotonebot/kaa/sprites/{c577c19e-aa5d-4670-b44c-1c0b3d72451a.png → 452e213a-9762-42ec-8e2b-2cabc3eb254d.png} +0 -0
- /kotonebot/kaa/sprites/{79226566-26e2-4c2f-8f6a-4e4deb9fa9ea.png → 46a8bf3e-7149-4d9b-8b31-a6b9c3d6b166.png} +0 -0
- /kotonebot/kaa/sprites/{fd77088d-652a-472e-9f84-dcc83d40a6bf.png → 48293a53-d05b-4198-995f-103531f26923.png} +0 -0
- /kotonebot/kaa/sprites/{7f4accdd-bd72-45e6-8469-692e27986486.png → 4c0dc941-6ecf-45b4-91f8-3fb10e770512.png} +0 -0
- /kotonebot/kaa/sprites/{2cea06ca-99f6-4bc5-8dd0-2bba80b07b17.png → 50986ada-ff64-405f-911d-f6c3655fb658.png} +0 -0
- /kotonebot/kaa/sprites/{10a329df-2515-4551-a130-07e86058abdf.png → 535db21f-b22e-4a05-a7e8-81e3664305b8.png} +0 -0
- /kotonebot/kaa/sprites/{1609d037-a3fc-485b-96c6-cf1790434c01.png → 5410568f-2e3c-49b2-8112-f43c52342298.png} +0 -0
- /kotonebot/kaa/sprites/{d627ba81-9c86-4b53-9ab9-86c8748d8daa.png → 5aa47ea4-79de-4547-9320-cf8c614c7366.png} +0 -0
- /kotonebot/kaa/sprites/{a77c1724-eb8f-4a1a-8997-516deb75ae78.png → 5d1627a0-f803-4736-8c3c-7bf1f0de0aa0.png} +0 -0
- /kotonebot/kaa/sprites/{88945ecf-9ac5-46dc-8af6-b21dbfded665.png → 5eaa9fa9-0bce-47ce-8f28-d5ba32c566c3.png} +0 -0
- /kotonebot/kaa/sprites/{63cd694d-343e-468d-a53f-360c97f71ee6.png → 650eee06-c926-4e91-bd2c-38f3068938c0.png} +0 -0
- /kotonebot/kaa/sprites/{5aef61f9-d616-42f2-ae8d-5c5a033231d3.png → 652c9b9f-316e-46b2-a2d4-8dc8d5e6116f.png} +0 -0
- /kotonebot/kaa/sprites/{d83f2631-b9d8-4fd6-ab1c-50b0a013f3f0.png → 6621d884-5ba5-4356-bd50-94239ec5395a.png} +0 -0
- /kotonebot/kaa/sprites/{dcc214f3-9707-4a2c-aaff-3834e6f12f0b.png → 66de3573-9562-4cd8-82df-5d6be6b1f213.png} +0 -0
- /kotonebot/kaa/sprites/{a5d3efa4-ec3e-4637-835a-147af973bbf8.png → 6b71968e-97d3-4fad-89d0-ffb7743446a9.png} +0 -0
- /kotonebot/kaa/sprites/{f16d6f1e-b9ff-4cff-aed3-dd150caf8f07.png → 6c7cb85e-0aac-40d8-9b55-d9b455c89985.png} +0 -0
- /kotonebot/kaa/sprites/{1bb92c94-af17-492e-9d22-393c12b7f346.png → 6cba0d0c-a67b-470d-9abe-1c55b14310ba.png} +0 -0
- /kotonebot/kaa/sprites/{731ed76d-6d6c-48b9-82c3-045cc1ecc419.png → 6d59fa9e-b988-47e3-99b5-e06510f98e45.png} +0 -0
- /kotonebot/kaa/sprites/{04425af8-ba28-407d-ad18-8c3a2483025d.png → 6eb8e6a5-b361-4c4f-b161-e2ccd5ef277d.png} +0 -0
- /kotonebot/kaa/sprites/{e36ec591-8bf5-4deb-9f28-3977576de931.png → 6ed77f5b-e4ce-4722-934e-3c5ec34b6d5a.png} +0 -0
- /kotonebot/kaa/sprites/{8e0964c4-6e34-43cb-a333-d60bceae7f11.png → 6f4d32df-2a01-40e8-bfd1-9e83c6864789.png} +0 -0
- /kotonebot/kaa/sprites/{41f0e90a-a352-450c-a788-0303d038227a.png → 6f56551e-bfa3-4efe-b95a-411e54885ceb.png} +0 -0
- /kotonebot/kaa/sprites/{d54fc8f5-e50d-45dd-b123-92414f93488c.png → 725d6877-7260-4ca3-91d3-da4e9ccbf206.png} +0 -0
- /kotonebot/kaa/sprites/{d14633f5-9682-4b59-a4ef-e92a2d26d86b.png → 74bb6050-8d6d-48aa-8e71-31e92304b5af.png} +0 -0
- /kotonebot/kaa/sprites/{a009c9de-029e-4999-b728-e6877374325a.png → 760655f5-1d32-437c-81fc-306e80fabfd8.png} +0 -0
- /kotonebot/kaa/sprites/{487ae483-2787-4982-93b0-4847665683e9.png → 763968fd-f7ab-4a46-a0ef-6a496b21d3dd.png} +0 -0
- /kotonebot/kaa/sprites/{0e4b4481-6805-4a1b-a3d8-913681968662.png → 77b7b404-bc0c-4637-96b0-7344f782989e.png} +0 -0
- /kotonebot/kaa/sprites/{fef40be1-5b75-4023-9977-df46cd211a86.png → 79cddeac-828b-49a1-b860-b422e2c8d2ea.png} +0 -0
- /kotonebot/kaa/sprites/{3645c21a-acd8-4ec4-a286-d9031736342c.png → 7b74cacf-b8b4-4915-a71a-1dab321dab60.png} +0 -0
- /kotonebot/kaa/sprites/{c92a2935-cf41-4f56-911a-bc40f122cbf3.png → 7d931bd2-5cfc-4e4c-83c0-498b5e17d15c.png} +0 -0
- /kotonebot/kaa/sprites/{2bb9dbf7-6cb2-426a-a35c-7228a1320220.png → 7dc4ea14-42a9-4b2f-a164-99da3dbb000b.png} +0 -0
- /kotonebot/kaa/sprites/{df9d09c3-8f15-4caf-bb21-f69644fb4705.png → 7dc5f386-2db3-4405-9796-34f1b8a6755f.png} +0 -0
- /kotonebot/kaa/sprites/{40f04ad0-44c0-4913-89aa-bc466bfd6ace.png → 843174a9-6cff-45ba-9573-67904691a30f.png} +0 -0
- /kotonebot/kaa/sprites/{ddae5592-adc3-4c36-bfdd-6c6d91823296.png → 85ca40d2-f02e-45a4-9db0-c483f6ae1db5.png} +0 -0
- /kotonebot/kaa/sprites/{15fe6944-396c-467b-80db-476bbdf65a80.png → 88207e47-1f50-485f-9984-54cea01d740a.png} +0 -0
- /kotonebot/kaa/sprites/{49ccf947-13a5-4839-8f85-d0fe40094e77.png → 88e01e80-50e2-4b0f-834c-86f6a3508287.png} +0 -0
- /kotonebot/kaa/sprites/{a4553bb1-27b9-47c4-8f51-1cff2129df8e.png → 89b364ae-9050-4671-b595-632ba0efc78b.png} +0 -0
- /kotonebot/kaa/sprites/{2cff833f-10bd-478c-8760-99162c71e9e3.png → 8d1a63f3-7ec4-405c-9d78-d176018389dc.png} +0 -0
- /kotonebot/kaa/sprites/{6e59d072-06f8-488f-a453-8ba60a05d691.png → 8f941a44-bbe8-4d3d-82b3-7b14c2356998.png} +0 -0
- /kotonebot/kaa/sprites/{183df82f-acea-4d40-87a8-18fc8ddab6d0.png → 95962144-c639-4902-ad2d-be11ccc5eaab.png} +0 -0
- /kotonebot/kaa/sprites/{a3384f38-334c-440a-ab06-405bad293bab.png → 96c79132-d55f-43d2-bdb3-6fe55734b6d5.png} +0 -0
- /kotonebot/kaa/sprites/{3fc47270-febf-492e-b8fc-0a9793bc0d56.png → 9895c28f-eba2-4e37-911b-6c0f05f7d72b.png} +0 -0
- /kotonebot/kaa/sprites/{bc01675d-453c-43f2-9075-f9567c8aa6f9.png → 98df22d6-1ff2-4c9a-87e7-f70e9f91019e.png} +0 -0
- /kotonebot/kaa/sprites/{71d6a37d-45df-456f-b673-d1e8b35ee619.png → 9b01dbe2-5043-40af-858c-33bbbf4ccc22.png} +0 -0
- /kotonebot/kaa/sprites/{fda67b44-d46d-4789-89a3-0786c60987ab.png → 9dc9f428-6e6d-4362-b4d4-dce50d9e732e.png} +0 -0
- /kotonebot/kaa/sprites/{3a595ec9-d813-4c09-b8b8-be8f5da88faa.png → 9df02971-cdd8-4464-abf9-8035bc233d2f.png} +0 -0
- /kotonebot/kaa/sprites/{d81b7022-5c81-4533-b949-7e9d75a5b8b4.png → 9e7bf71b-fe8d-43cf-8bdd-6cfb1fb1b597.png} +0 -0
- /kotonebot/kaa/sprites/{2dab2877-c6c3-45d9-849f-fb2d79b7b74e.png → a043ed15-0ceb-49b5-b3df-d03274677340.png} +0 -0
- /kotonebot/kaa/sprites/{6582463d-b4fa-40a1-b771-664c7f71fe9c.png → a200b1e4-2ebc-4c15-bdf2-2575408877f8.png} +0 -0
- /kotonebot/kaa/sprites/{9449ff36-7adb-42d5-b89d-bf9147d62811.png → a718a6f9-db30-4a9c-9d2b-b83055cf36ae.png} +0 -0
- /kotonebot/kaa/sprites/{966bcfd4-fefc-4704-907d-45bc6098d3f4.png → a7ada2b7-1366-40c8-864e-fbb42d248124.png} +0 -0
- /kotonebot/kaa/sprites/{b6f5243b-cfb4-42d2-b4eb-2fd1a9d33ab7.png → aa42da27-2c6a-4731-9678-edd3aefde4a7.png} +0 -0
- /kotonebot/kaa/sprites/{0002785c-3caa-4c8f-8d47-f29aee04a588.png → aaa770da-fc42-4e4a-978c-8fef22c0ebf9.png} +0 -0
- /kotonebot/kaa/sprites/{83f9e9a0-54dd-4601-8e54-3091c2892e67.png → af54e00c-b768-4497-829b-6bfac16f4efc.png} +0 -0
- /kotonebot/kaa/sprites/{0554264f-0474-44d0-9209-8135d8840c53.png → afe94aea-47e2-4310-8e25-3e7cadc5a75d.png} +0 -0
- /kotonebot/kaa/sprites/{0a4c6cbe-f42e-4301-9c1a-101fc33421d2.png → b0a88b9e-358f-4f35-b823-d6c025a516cf.png} +0 -0
- /kotonebot/kaa/sprites/{b25627d6-3352-4fe8-93c2-b653efe104d4.png → b4ede50d-7edb-4461-bee6-77d13456fa30.png} +0 -0
- /kotonebot/kaa/sprites/{f5727018-9a23-40de-840e-610d6e5dfa9d.png → b503e883-c9d2-46c0-9de2-158770abb32b.png} +0 -0
- /kotonebot/kaa/sprites/{92a42da1-d8d2-4233-b6d0-5997a72f3d03.png → b60b3563-20b4-46ad-b36b-3113d9e07d4c.png} +0 -0
- /kotonebot/kaa/sprites/{67f00dd1-86c9-4a49-a37c-87879171a46a.png → b9ded3ea-9701-441d-a593-e73e44d5fa3f.png} +0 -0
- /kotonebot/kaa/sprites/{be83e205-8ec5-452f-b42b-b98156516aa8.png → b9f285e4-eb97-47f0-9ca5-28ca558acf58.png} +0 -0
- /kotonebot/kaa/sprites/{6cacdb8f-2ea3-4e3c-a124-b957b75ea427.png → bbee032e-7fc1-4b4d-b1db-cc54b24c20c8.png} +0 -0
- /kotonebot/kaa/sprites/{401966c8-2095-4eef-b92a-764122de02d9.png → bc68fbda-8e6d-4368-b322-49a6854d81e3.png} +0 -0
- /kotonebot/kaa/sprites/{12151e09-e5f1-4b1d-a211-63cb300cb082.png → bf8d6419-472c-4941-8d69-9bb01af5c71a.png} +0 -0
- /kotonebot/kaa/sprites/{9d80c1ef-0f42-4622-ab9a-bfcc077dace6.png → c3548011-dc57-4542-a855-1e7f9d7762f7.png} +0 -0
- /kotonebot/kaa/sprites/{8fb17c7f-778d-4cd5-8d2f-dbf21d264297.png → c46f1705-b4d5-4f39-b138-391a85fb0302.png} +0 -0
- /kotonebot/kaa/sprites/{f58c3a84-60ea-415b-ac63-4b534dc8cb6c.png → c58be1dd-1981-42ee-8de3-e365102884e5.png} +0 -0
- /kotonebot/kaa/sprites/{dd699396-5500-43ad-8470-cf7a8ba013ec.png → c8321b5a-8f65-4465-892a-a3432efba5ac.png} +0 -0
- /kotonebot/kaa/sprites/{e89c23b0-ca58-49d1-b439-967a4a4a431d.png → c95ee1bb-1e53-4568-ba92-9606071ad3a6.png} +0 -0
- /kotonebot/kaa/sprites/{e04331fe-d62e-4f77-953d-78515ee5686e.png → ca9f52b1-42c0-4091-bc29-efc0da9606e0.png} +0 -0
- /kotonebot/kaa/sprites/{d56feb26-d560-423f-b5f8-dc06f7a3c8a1.png → ccba7903-9882-4982-ab84-355667d8419a.png} +0 -0
- /kotonebot/kaa/sprites/{e4a92c92-0974-40e0-b488-16ea7a4c1a29.png → d0dd43b7-5571-4e47-af51-796b4a6a1cfe.png} +0 -0
- /kotonebot/kaa/sprites/{e075c8cb-7eef-47cf-b9fe-9e3d1bd98e85.png → d274bf4d-f4ff-4270-9a5f-87685a0c6817.png} +0 -0
- /kotonebot/kaa/sprites/{64298c97-baac-48b9-be7d-cb14091aa3cb.png → d3565383-91b0-4b33-87a9-3468dfd56e52.png} +0 -0
- /kotonebot/kaa/sprites/{c3562fef-44f7-43d2-a4e6-e7ee21f8bdc5.png → d552db90-8e22-427c-b004-1799adbcc6ba.png} +0 -0
- /kotonebot/kaa/sprites/{681157d7-b37f-442f-b784-86fa9029ecdb.png → d5943dc2-12df-42bb-84bc-d6958260cb75.png} +0 -0
- /kotonebot/kaa/sprites/{10d9a788-24a2-42e1-9284-78f507986606.png → d5be0aac-6f00-4961-b21c-4075bd6ca528.png} +0 -0
- /kotonebot/kaa/sprites/{c5774fb4-be11-4b28-8f58-299ae8872cc1.png → d65cf124-6c8e-41e4-80dc-0c63b41d5636.png} +0 -0
- /kotonebot/kaa/sprites/{9a9d9398-15df-46ea-a247-04ba01f61603.png → d79069c1-3b8e-4df7-8b14-4eeaa44241e1.png} +0 -0
- /kotonebot/kaa/sprites/{5d3b3a20-89bb-4cf2-9973-25581c32e91c.png → db3ab847-948d-4ee0-b5cb-c57c0caa24fd.png} +0 -0
- /kotonebot/kaa/sprites/{610ea09a-d623-428f-ac97-1b51dc5e9202.png → dbc449e9-404e-435b-8b0f-3c853c7f0efe.png} +0 -0
- /kotonebot/kaa/sprites/{25f18ff9-dbae-4aed-87b4-c05ca6c4ebf4.png → dc3f2602-1f20-460a-b408-693001aa70bc.png} +0 -0
- /kotonebot/kaa/sprites/{f217d7cf-acf5-44eb-9f99-025bbcaea866.png → dcb63213-c81e-4eb7-82f1-a16a838299fe.png} +0 -0
- /kotonebot/kaa/sprites/{bcc433e0-8a4e-455f-b625-4583cea19c1c.png → df004f6b-683d-41e8-848f-2a838c585f43.png} +0 -0
- /kotonebot/kaa/sprites/{94021aa4-fb87-41e7-920a-988a360f8321.png → dfab89de-7365-4bc8-b332-6f62733123a2.png} +0 -0
- /kotonebot/kaa/sprites/{12d0271c-1a86-4d2c-b379-b7df847fe20b.png → e0a34a9a-69b6-4732-9b1c-7a2c6445cb76.png} +0 -0
- /kotonebot/kaa/sprites/{e281792b-000b-4048-afb7-e8bb0dbd88b3.png → e0cea27c-5b4e-4831-8fcf-65bccb9e5950.png} +0 -0
- /kotonebot/kaa/sprites/{a514ce10-bff1-4aa0-9625-bf560dcb8be5.png → e311e99e-ae64-442a-aed1-6fac29687d18.png} +0 -0
- /kotonebot/kaa/sprites/{9dfa46c9-54ec-4dd7-8f2e-e1e66c1206f1.png → e8e25d3c-569e-4eae-a707-3afa8c5f46ec.png} +0 -0
- /kotonebot/kaa/sprites/{951ae4be-40f3-4ccc-8578-77aca7f25eef.png → e9afeef0-fcbe-4d97-8b39-c57ab24a3f84.png} +0 -0
- /kotonebot/kaa/sprites/{8a2938ad-5657-4f66-8447-4bc7fa45b857.png → ec9656c3-a984-47db-8661-e1ae8751d288.png} +0 -0
- /kotonebot/kaa/sprites/{377857a9-c37f-4a90-afa9-00c4ff7b24ae.png → ee4862f3-f298-446e-a68b-bd97259052e6.png} +0 -0
- /kotonebot/kaa/sprites/{3e34e821-ae69-49aa-9d04-bc34b3037cd5.png → ef585824-7bfa-427a-a185-4317c0bcb4f6.png} +0 -0
- /kotonebot/kaa/sprites/{87c7532f-2394-403e-a6d8-7a216043ec13.png → ef861253-914d-436e-aa01-731a5dd11e38.png} +0 -0
- /kotonebot/kaa/sprites/{97a543a8-a859-4a1e-8e33-602f600db389.png → f0b983cd-8bce-4b67-9214-493364244c26.png} +0 -0
- /kotonebot/kaa/sprites/{143db8eb-fdde-4de0-a946-a14123b9262e.png → f2906fc0-9192-48ca-bc5d-52e922b04d8d.png} +0 -0
- /kotonebot/kaa/sprites/{f543861e-c3d5-4bc9-a677-47f9e86918ea.png → f3890caa-fa8b-43bc-ba30-82c5bbe1d12a.png} +0 -0
- /kotonebot/kaa/sprites/{d6314592-b8a4-4025-9875-b135bf986cf7.png → f4c3a6f9-1149-4530-af30-c56d7e3d02b9.png} +0 -0
- /kotonebot/kaa/sprites/{1f9f101b-2647-4d14-931e-7a8307495475.png → fa3bdcef-dfba-4cf2-a06f-e6078c07fb7d.png} +0 -0
- /kotonebot/kaa/sprites/{9e0492b7-3b66-48a2-b589-91e7fd16106d.png → fab770fd-e250-4dd4-b9d2-80966ad452ac.png} +0 -0
- /kotonebot/kaa/sprites/{f2d8a534-8afd-475c-ac20-738c7efffc90.png → fb2f308f-a025-4606-b789-0455c7cf0af8.png} +0 -0
- /kotonebot/kaa/sprites/{4622e955-7bb1-450d-a776-01543540fde3.png → fcc71fcd-b28e-4247-beb6-6f5422218c54.png} +0 -0
- /kotonebot/kaa/sprites/{04feeecc-a607-402d-bbc4-a71af87c7fc2.png → fe42018b-4987-4389-8d44-fb0cfd0f4dab.png} +0 -0
- {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.0.dist-info}/WHEEL +0 -0
- {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.0.dist-info}/entry_points.txt +0 -0
- {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.0.dist-info}/licenses/LICENSE +0 -0
- {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.0.dist-info}/top_level.txt +0 -0
kotonebot/backend/bot.py
CHANGED
|
@@ -12,6 +12,15 @@ from kotonebot.client import Device
|
|
|
12
12
|
from kotonebot.client.host.protocol import Instance
|
|
13
13
|
from kotonebot.backend.context import init_context, vars
|
|
14
14
|
from kotonebot.backend.context import task_registry, action_registry, Task, Action
|
|
15
|
+
from kotonebot.errors import StopCurrentTask, UserFriendlyError
|
|
16
|
+
from kotonebot.interop.win.task_dialog import TaskDialog
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class PostTaskContext:
|
|
21
|
+
has_error: bool
|
|
22
|
+
exception: Exception | None
|
|
23
|
+
|
|
15
24
|
|
|
16
25
|
log_stream = io.StringIO()
|
|
17
26
|
stream_handler = logging.StreamHandler(log_stream)
|
|
@@ -19,10 +28,11 @@ stream_handler.setFormatter(logging.Formatter('[%(asctime)s] [%(levelname)s] [%(
|
|
|
19
28
|
logging.getLogger('kotonebot').addHandler(stream_handler)
|
|
20
29
|
logger = logging.getLogger(__name__)
|
|
21
30
|
|
|
31
|
+
TaskStatusValue = Literal['pending', 'running', 'finished', 'error', 'cancelled', 'stopped']
|
|
22
32
|
@dataclass
|
|
23
33
|
class TaskStatus:
|
|
24
34
|
task: Task
|
|
25
|
-
status:
|
|
35
|
+
status: TaskStatusValue
|
|
26
36
|
|
|
27
37
|
@dataclass
|
|
28
38
|
class RunStatus:
|
|
@@ -73,7 +83,7 @@ class Event(Generic[Params, Return]):
|
|
|
73
83
|
class KotoneBotEvents:
|
|
74
84
|
def __init__(self):
|
|
75
85
|
self.task_status_changed = Event[
|
|
76
|
-
[Task,
|
|
86
|
+
[Task, TaskStatusValue], None
|
|
77
87
|
]()
|
|
78
88
|
self.task_error = Event[
|
|
79
89
|
[Task, Exception], None
|
|
@@ -171,42 +181,80 @@ class KotoneBot:
|
|
|
171
181
|
self._on_after_init_context()
|
|
172
182
|
vars.flow.clear_interrupt()
|
|
173
183
|
|
|
184
|
+
pre_tasks = [task for task in tasks if task.run_at == 'pre']
|
|
185
|
+
regular_tasks = [task for task in tasks if task.run_at == 'regular']
|
|
186
|
+
post_tasks = [task for task in tasks if task.run_at == 'post']
|
|
187
|
+
|
|
174
188
|
if by_priority:
|
|
175
|
-
|
|
176
|
-
|
|
189
|
+
pre_tasks = sorted(pre_tasks, key=lambda x: x.priority, reverse=True)
|
|
190
|
+
regular_tasks = sorted(regular_tasks, key=lambda x: x.priority, reverse=True)
|
|
191
|
+
post_tasks = sorted(post_tasks, key=lambda x: x.priority, reverse=True)
|
|
192
|
+
|
|
193
|
+
all_tasks = pre_tasks + regular_tasks + post_tasks
|
|
194
|
+
for task in all_tasks:
|
|
177
195
|
self.events.task_status_changed.trigger(task, 'pending')
|
|
178
196
|
|
|
179
|
-
|
|
197
|
+
has_error = False
|
|
198
|
+
exception: Exception | None = None
|
|
199
|
+
|
|
200
|
+
for task in all_tasks:
|
|
180
201
|
logger.info(f'Task started: {task.name}')
|
|
181
202
|
self.events.task_status_changed.trigger(task, 'running')
|
|
182
203
|
|
|
183
204
|
if self.debug:
|
|
184
|
-
task.
|
|
205
|
+
if task.run_at == 'post':
|
|
206
|
+
task.func(PostTaskContext(has_error, exception))
|
|
207
|
+
else:
|
|
208
|
+
task.func()
|
|
185
209
|
else:
|
|
186
210
|
try:
|
|
187
|
-
task.
|
|
211
|
+
if task.run_at == 'post':
|
|
212
|
+
task.func(PostTaskContext(has_error, exception))
|
|
213
|
+
else:
|
|
214
|
+
task.func()
|
|
188
215
|
self.events.task_status_changed.trigger(task, 'finished')
|
|
216
|
+
except StopCurrentTask:
|
|
217
|
+
logger.info(f'Task skipped/stopped: {task.name}')
|
|
218
|
+
self.events.task_status_changed.trigger(task, 'stopped')
|
|
189
219
|
# 用户中止
|
|
190
220
|
except KeyboardInterrupt as e:
|
|
191
221
|
logger.exception('Keyboard interrupt detected.')
|
|
192
|
-
for task1 in
|
|
222
|
+
for task1 in all_tasks[all_tasks.index(task):]:
|
|
193
223
|
self.events.task_status_changed.trigger(task1, 'cancelled')
|
|
194
224
|
vars.flow.clear_interrupt()
|
|
195
225
|
break
|
|
226
|
+
# 用户可以自行处理的错误
|
|
227
|
+
except UserFriendlyError as e:
|
|
228
|
+
logger.error(f'Task failed: {task.name}')
|
|
229
|
+
logger.exception(f'Error: ')
|
|
230
|
+
has_error = True
|
|
231
|
+
exception = e
|
|
232
|
+
dialog = TaskDialog(
|
|
233
|
+
title='琴音小助手',
|
|
234
|
+
common_buttons=0,
|
|
235
|
+
main_instruction='任务执行失败',
|
|
236
|
+
content=e.message,
|
|
237
|
+
custom_buttons=e.action_buttons,
|
|
238
|
+
main_icon='error'
|
|
239
|
+
)
|
|
240
|
+
result_custom, _, _ = dialog.show()
|
|
241
|
+
e.invoke(result_custom)
|
|
196
242
|
# 其他错误
|
|
197
243
|
except Exception as e:
|
|
198
244
|
logger.error(f'Task failed: {task.name}')
|
|
199
245
|
logger.exception(f'Error: ')
|
|
246
|
+
has_error = True
|
|
247
|
+
exception = e
|
|
200
248
|
report_path = None
|
|
201
249
|
if self.auto_save_error_report:
|
|
202
250
|
raise NotImplementedError
|
|
203
251
|
self.events.task_status_changed.trigger(task, 'error')
|
|
204
252
|
if not self.resume_on_error:
|
|
205
|
-
for task1 in
|
|
253
|
+
for task1 in all_tasks[all_tasks.index(task)+1:]:
|
|
206
254
|
self.events.task_status_changed.trigger(task1, 'cancelled')
|
|
207
255
|
break
|
|
208
|
-
logger.info(f'Task
|
|
209
|
-
logger.info('All tasks
|
|
256
|
+
logger.info(f'Task ended: {task.name}')
|
|
257
|
+
logger.info('All tasks ended.')
|
|
210
258
|
self.events.finished.trigger()
|
|
211
259
|
|
|
212
260
|
def run_all(self) -> None:
|
|
@@ -228,7 +276,7 @@ class KotoneBot:
|
|
|
228
276
|
self.events.finished -= _on_finished
|
|
229
277
|
self.events.task_status_changed -= _on_task_status_changed
|
|
230
278
|
|
|
231
|
-
def _on_task_status_changed(task: Task, status:
|
|
279
|
+
def _on_task_status_changed(task: Task, status: TaskStatusValue):
|
|
232
280
|
def _find(task: Task) -> TaskStatus:
|
|
233
281
|
for task_status in run_status.tasks:
|
|
234
282
|
if task_status.task == task:
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Callable, ParamSpec, TypeVar, overload,
|
|
2
|
+
from typing import Callable, ParamSpec, TypeVar, overload, Literal
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing_extensions import deprecated
|
|
5
4
|
|
|
6
|
-
import cv2
|
|
7
|
-
from cv2.typing import MatLike
|
|
8
5
|
|
|
9
6
|
from .context import ContextStackVars, ScreenshotMode
|
|
10
|
-
from ..dispatch import dispatcher as dispatcher_decorator, DispatcherContext
|
|
11
7
|
from ...errors import TaskNotFoundError
|
|
12
8
|
|
|
13
9
|
P = ParamSpec('P')
|
|
14
10
|
R = TypeVar('R')
|
|
15
11
|
logger = logging.getLogger(__name__)
|
|
16
12
|
|
|
13
|
+
TaskRunAtType = Literal['pre', 'post', 'manual', 'regular'] | str
|
|
14
|
+
|
|
15
|
+
|
|
17
16
|
@dataclass
|
|
18
17
|
class Task:
|
|
19
18
|
name: str
|
|
@@ -24,6 +23,8 @@ class Task:
|
|
|
24
23
|
"""
|
|
25
24
|
任务优先级,数字越大优先级越高。
|
|
26
25
|
"""
|
|
26
|
+
run_at: TaskRunAtType = 'regular'
|
|
27
|
+
|
|
27
28
|
|
|
28
29
|
@dataclass
|
|
29
30
|
class Action:
|
|
@@ -51,6 +52,7 @@ def task(
|
|
|
51
52
|
pass_through: bool = False,
|
|
52
53
|
priority: int = 0,
|
|
53
54
|
screenshot_mode: ScreenshotMode = 'auto',
|
|
55
|
+
run_at: TaskRunAtType = 'regular'
|
|
54
56
|
):
|
|
55
57
|
"""
|
|
56
58
|
`task` 装饰器,用于标记一个函数为任务函数。
|
|
@@ -62,6 +64,7 @@ def task(
|
|
|
62
64
|
默认情况下, @task 装饰器会包裹任务函数,跟踪其执行情况。
|
|
63
65
|
如果不想跟踪,则设置此参数为 False。
|
|
64
66
|
:param priority: 任务优先级,数字越大优先级越高。
|
|
67
|
+
:param run_at: 任务运行时间。
|
|
65
68
|
"""
|
|
66
69
|
# 设置 ID
|
|
67
70
|
# 获取 caller 信息
|
|
@@ -70,7 +73,7 @@ def task(
|
|
|
70
73
|
description = description or func.__doc__ or ''
|
|
71
74
|
# TODO: task_id 冲突检测
|
|
72
75
|
task_id = task_id or func.__name__
|
|
73
|
-
task = Task(name, task_id, description, _placeholder, priority)
|
|
76
|
+
task = Task(name, task_id, description, _placeholder, priority, run_at)
|
|
74
77
|
task_registry[name] = task
|
|
75
78
|
logger.debug(f'Task "{name}" registered.')
|
|
76
79
|
if pass_through:
|
|
@@ -98,7 +101,6 @@ def action(
|
|
|
98
101
|
pass_through: bool = False,
|
|
99
102
|
priority: int = 0,
|
|
100
103
|
screenshot_mode: ScreenshotMode | None = None,
|
|
101
|
-
dispatcher: Literal[False] = False,
|
|
102
104
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
103
105
|
"""
|
|
104
106
|
`action` 装饰器,用于标记一个函数为动作函数。
|
|
@@ -110,38 +112,6 @@ def action(
|
|
|
110
112
|
如果不想跟踪,则设置此参数为 False。
|
|
111
113
|
:param priority: 动作优先级,数字越大优先级越高。
|
|
112
114
|
:param screenshot_mode: 截图模式。
|
|
113
|
-
:param dispatcher:
|
|
114
|
-
是否为分发器模式。默认为假。
|
|
115
|
-
如果使用分发器,则函数的第一个参数必须为 `ctx: DispatcherContext`。
|
|
116
|
-
"""
|
|
117
|
-
...
|
|
118
|
-
|
|
119
|
-
@overload
|
|
120
|
-
@deprecated('使用普通 while 循环代替')
|
|
121
|
-
def action(
|
|
122
|
-
name: str,
|
|
123
|
-
*,
|
|
124
|
-
description: str|None = None,
|
|
125
|
-
pass_through: bool = False,
|
|
126
|
-
priority: int = 0,
|
|
127
|
-
screenshot_mode: ScreenshotMode | None = None,
|
|
128
|
-
dispatcher: Literal[True, 'fragment'] = True,
|
|
129
|
-
) -> Callable[[Callable[Concatenate[DispatcherContext, P], R]], Callable[P, R]]:
|
|
130
|
-
"""
|
|
131
|
-
`action` 装饰器,用于标记一个函数为动作函数。
|
|
132
|
-
|
|
133
|
-
此重载启用了分发器模式。被装饰函数的第一个参数必须为 `ctx: DispatcherContext`。
|
|
134
|
-
|
|
135
|
-
:param name: 动作名称。如果为 None,则使用函数的名称作为名称。
|
|
136
|
-
:param description: 动作描述。如果为 None,则使用函数的 docstring 作为描述。
|
|
137
|
-
:param pass_through:
|
|
138
|
-
默认情况下, @action 装饰器会包裹动作函数,跟踪其执行情况。
|
|
139
|
-
如果不想跟踪,则设置此参数为 False。
|
|
140
|
-
:param priority: 动作优先级,数字越大优先级越高。
|
|
141
|
-
:param screenshot_mode: 截图模式,必须为 `'manual' / None`。
|
|
142
|
-
:param dispatcher:
|
|
143
|
-
是否为分发器模式。默认为假。
|
|
144
|
-
如果使用分发器,则函数的第一个参数必须为 `ctx: DispatcherContext`。
|
|
145
115
|
"""
|
|
146
116
|
...
|
|
147
117
|
|
|
@@ -176,11 +146,6 @@ def action(*args, **kwargs):
|
|
|
176
146
|
pass_through = kwargs.get('pass_through', False)
|
|
177
147
|
priority = kwargs.get('priority', 0)
|
|
178
148
|
screenshot_mode = kwargs.get('screenshot_mode', None)
|
|
179
|
-
dispatcher = kwargs.get('dispatcher', False)
|
|
180
|
-
if dispatcher == True or dispatcher == 'fragment':
|
|
181
|
-
if not (screenshot_mode is None or screenshot_mode == 'manual'):
|
|
182
|
-
raise ValueError('`screenshot_mode` must be None or "manual" when `dispatcher=True`.')
|
|
183
|
-
screenshot_mode = 'manual'
|
|
184
149
|
def _action_decorator(func: Callable):
|
|
185
150
|
nonlocal pass_through
|
|
186
151
|
action = _register(_placeholder, name, description)
|
|
@@ -188,8 +153,6 @@ def action(*args, **kwargs):
|
|
|
188
153
|
if pass_through:
|
|
189
154
|
return func
|
|
190
155
|
else:
|
|
191
|
-
if dispatcher:
|
|
192
|
-
func = dispatcher_decorator(func, fragment=(dispatcher == 'fragment')) # type: ignore
|
|
193
156
|
def _wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
194
157
|
current_callstack.append(action)
|
|
195
158
|
vars = ContextStackVars.push(screenshot_mode=screenshot_mode)
|
kotonebot/backend/dispatch.py
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import time
|
|
2
|
-
import uuid
|
|
3
2
|
import logging
|
|
4
|
-
import inspect
|
|
5
|
-
from logging import Logger
|
|
6
|
-
from types import CodeType
|
|
7
3
|
from dataclasses import dataclass
|
|
8
|
-
from typing import
|
|
9
|
-
from typing_extensions import deprecated
|
|
4
|
+
from typing import Any, Callable, Literal
|
|
10
5
|
|
|
11
6
|
from dataclasses import dataclass
|
|
12
7
|
|
|
@@ -16,104 +11,6 @@ from kotonebot.primitives import Rect, is_rect
|
|
|
16
11
|
from .core import Image
|
|
17
12
|
|
|
18
13
|
logger = logging.getLogger(__name__)
|
|
19
|
-
P = ParamSpec('P')
|
|
20
|
-
R = TypeVar('R')
|
|
21
|
-
ThenAction = Literal['click', 'log']
|
|
22
|
-
DoAction = Literal['click']
|
|
23
|
-
# TODO: 需要找个地方统一管理这些属性名
|
|
24
|
-
ATTR_DISPATCHER_MARK = '__kb_dispatcher_mark'
|
|
25
|
-
ATTR_ORIGINAL_FUNC = '_kb_inner'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class DispatchFunc: pass
|
|
29
|
-
|
|
30
|
-
wrapper_to_func: dict[Callable, Callable] = {}
|
|
31
|
-
|
|
32
|
-
class DispatcherContext:
|
|
33
|
-
def __init__(self):
|
|
34
|
-
self.finished: bool = False
|
|
35
|
-
self._first_run: bool = True
|
|
36
|
-
|
|
37
|
-
def finish(self):
|
|
38
|
-
"""标记已完成 dispatcher 循环。循环将在下次条件检测时退出。"""
|
|
39
|
-
self.finished = True
|
|
40
|
-
|
|
41
|
-
def expand(self, func: Annotated[Callable[[], Any], DispatchFunc], ignore_finish: bool = True):
|
|
42
|
-
"""
|
|
43
|
-
调用其他 dispatcher 函数。
|
|
44
|
-
|
|
45
|
-
使用 `expand` 和直接调用的区别是:
|
|
46
|
-
* 直接调用会执行 while 循环,直到满足结束条件
|
|
47
|
-
* 而使用 `expand` 则只会执行一次。效果类似于将目标函数里的代码直接复制粘贴过来。
|
|
48
|
-
"""
|
|
49
|
-
# 获取原始函数
|
|
50
|
-
original_func = func
|
|
51
|
-
while not getattr(original_func, ATTR_DISPATCHER_MARK, False):
|
|
52
|
-
original_func = getattr(original_func, ATTR_ORIGINAL_FUNC)
|
|
53
|
-
original_func = getattr(original_func, ATTR_ORIGINAL_FUNC)
|
|
54
|
-
|
|
55
|
-
if not original_func:
|
|
56
|
-
raise ValueError(f'{repr(func)} is not a dispatcher function.')
|
|
57
|
-
elif not callable(original_func):
|
|
58
|
-
raise ValueError(f'{repr(original_func)} is not callable.')
|
|
59
|
-
original_func = cast(Callable[[DispatcherContext], Any], original_func)
|
|
60
|
-
|
|
61
|
-
old_finished = self.finished
|
|
62
|
-
ret = original_func(self)
|
|
63
|
-
if ignore_finish:
|
|
64
|
-
self.finished = old_finished
|
|
65
|
-
return ret
|
|
66
|
-
|
|
67
|
-
@property
|
|
68
|
-
def beginning(self) -> bool:
|
|
69
|
-
"""是否为第一次运行"""
|
|
70
|
-
return self._first_run
|
|
71
|
-
|
|
72
|
-
@property
|
|
73
|
-
def finishing(self) -> bool:
|
|
74
|
-
"""是否即将结束运行"""
|
|
75
|
-
return self.finished
|
|
76
|
-
|
|
77
|
-
@deprecated('使用 SimpleDispatcher 类或 while 循环替代')
|
|
78
|
-
def dispatcher(
|
|
79
|
-
func: Callable[Concatenate[DispatcherContext, P], R],
|
|
80
|
-
*,
|
|
81
|
-
fragment: bool = False
|
|
82
|
-
) -> Annotated[Callable[P, R], DispatchFunc]:
|
|
83
|
-
"""
|
|
84
|
-
注意:\n
|
|
85
|
-
此装饰器必须在应用 @action/@task 装饰器后再应用,且 `screenshot_mode='manual'` 参数必须设置。
|
|
86
|
-
或者也可以使用 @action/@task 装饰器中的 `dispatcher=True` 参数,
|
|
87
|
-
那么就没有上面两个要求了。
|
|
88
|
-
|
|
89
|
-
:param fragment:
|
|
90
|
-
片段模式,默认不启用。
|
|
91
|
-
启用后,被装饰函数将会只执行依次,
|
|
92
|
-
而不会一直循环到 ctx.finish() 被调用。
|
|
93
|
-
"""
|
|
94
|
-
def wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
95
|
-
ctx = DispatcherContext()
|
|
96
|
-
while not ctx.finished:
|
|
97
|
-
from kotonebot import device
|
|
98
|
-
device.screenshot()
|
|
99
|
-
ret = func(ctx, *args, **kwargs)
|
|
100
|
-
ctx._first_run = False
|
|
101
|
-
return ret
|
|
102
|
-
def fragment_wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
103
|
-
ctx = DispatcherContext()
|
|
104
|
-
from kotonebot import device
|
|
105
|
-
device.screenshot()
|
|
106
|
-
return func(ctx, *args, **kwargs)
|
|
107
|
-
setattr(wrapper, ATTR_ORIGINAL_FUNC, func)
|
|
108
|
-
setattr(fragment_wrapper, ATTR_ORIGINAL_FUNC, func)
|
|
109
|
-
setattr(wrapper, ATTR_DISPATCHER_MARK, True)
|
|
110
|
-
setattr(fragment_wrapper, ATTR_DISPATCHER_MARK, True)
|
|
111
|
-
wrapper_to_func[wrapper] = func
|
|
112
|
-
if fragment:
|
|
113
|
-
return fragment_wrapper
|
|
114
|
-
|
|
115
|
-
else:
|
|
116
|
-
return wrapper
|
|
117
14
|
|
|
118
15
|
@dataclass
|
|
119
16
|
class ClickParams:
|
|
@@ -95,7 +95,7 @@ class FlowController:
|
|
|
95
95
|
logger.info('Interrupt requested.')
|
|
96
96
|
self.interrupt_event.set()
|
|
97
97
|
|
|
98
|
-
def request_pause(self) -> None:
|
|
98
|
+
def request_pause(self, *, wait_resume: bool = False) -> None:
|
|
99
99
|
"""
|
|
100
100
|
请求暂停任务。
|
|
101
101
|
|
|
@@ -106,6 +106,8 @@ class FlowController:
|
|
|
106
106
|
if not self.paused:
|
|
107
107
|
logger.info('Pause requested.')
|
|
108
108
|
self.paused = True
|
|
109
|
+
if wait_resume:
|
|
110
|
+
self.check()
|
|
109
111
|
|
|
110
112
|
def request_resume(self) -> None:
|
|
111
113
|
"""
|
kotonebot/errors.py
CHANGED
|
@@ -1,9 +1,41 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class KotonebotError(Exception):
|
|
2
5
|
pass
|
|
3
6
|
|
|
4
7
|
class KotonebotWarning(Warning):
|
|
5
8
|
pass
|
|
6
9
|
|
|
10
|
+
class UserFriendlyError(KotonebotError):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
message: str,
|
|
14
|
+
actions: list[tuple[int, str, Callable[[], None]]] = [],
|
|
15
|
+
*args, **kwargs
|
|
16
|
+
) -> None:
|
|
17
|
+
super().__init__(*args, **kwargs)
|
|
18
|
+
self.message = message
|
|
19
|
+
self.actions = actions or []
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def action_buttons(self) -> list[tuple[int, str]]:
|
|
23
|
+
"""
|
|
24
|
+
以 (id: int, btn_text: str) 的形式返回所有按钮定义。
|
|
25
|
+
"""
|
|
26
|
+
return [(id, text) for id, text, _ in self.actions]
|
|
27
|
+
|
|
28
|
+
def invoke(self, action_id: int):
|
|
29
|
+
"""
|
|
30
|
+
执行指定 ID 的 action。
|
|
31
|
+
"""
|
|
32
|
+
for id, _, func in self.actions:
|
|
33
|
+
if id == action_id:
|
|
34
|
+
func()
|
|
35
|
+
break
|
|
36
|
+
else:
|
|
37
|
+
raise ValueError(f'Action with id {action_id} not found.')
|
|
38
|
+
|
|
7
39
|
class UnrecoverableError(KotonebotError):
|
|
8
40
|
pass
|
|
9
41
|
|
|
@@ -31,7 +63,10 @@ class UnscalableResolutionError(KotonebotError):
|
|
|
31
63
|
self.screen_size = screen_size
|
|
32
64
|
super().__init__(f'Cannot scale to target resolution {target_resolution}. '
|
|
33
65
|
f'Screen size: {screen_size}')
|
|
34
|
-
|
|
66
|
+
|
|
35
67
|
class ContextNotInitializedError(KotonebotError):
|
|
36
68
|
def __init__(self, msg: str = 'Context not initialized'):
|
|
37
|
-
super().__init__(msg)
|
|
69
|
+
super().__init__(msg)
|
|
70
|
+
|
|
71
|
+
class StopCurrentTask(KotonebotError):
|
|
72
|
+
pass
|