ksaa 2025.5.23.3__py3-none-any.whl → 2025.6.8.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.
Files changed (155) hide show
  1. kotonebot/backend/bot.py +3 -3
  2. kotonebot/backend/context/context.py +21 -11
  3. kotonebot/backend/debug/server.py +3 -3
  4. kotonebot/backend/flow_controller.py +195 -0
  5. kotonebot/client/implements/windows.py +18 -13
  6. kotonebot/kaa/common.py +21 -0
  7. kotonebot/kaa/main/gr.py +156 -26
  8. kotonebot/kaa/metadata.py +12 -0
  9. kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  10. kotonebot/kaa/resources/game.db +0 -0
  11. kotonebot/kaa/resources/game_ver.txt +0 -0
  12. kotonebot/kaa/tasks/R.py +133 -133
  13. kotonebot/kaa/tasks/end_game.py +14 -0
  14. kotonebot/kaa/tasks/produce/common.py +1 -0
  15. kotonebot/kaa/tasks/produce/non_lesson_actions.py +1 -1
  16. kotonebot/kaa/tasks/start_game.py +49 -1
  17. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.8.0.dist-info}/METADATA +38 -1
  18. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.8.0.dist-info}/RECORD +155 -153
  19. ksaa-2025.6.8.0.dist-info/licenses/LICENSE +674 -0
  20. /kotonebot/kaa/sprites/{d364470a-d077-405f-a242-0d4fad32bc40.png → 02e0aa0d-4094-4bdc-8625-1a063733615b.png} +0 -0
  21. /kotonebot/kaa/sprites/{b3f1b38f-77d0-4dd5-8c19-8a35bbc39516.png → 03458cf9-8ab0-4908-9a56-9c5c7e06bc9b.png} +0 -0
  22. /kotonebot/kaa/sprites/{7079f76b-e2a3-487c-8616-28ce505f5a0e.png → 0439399f-5fca-43f9-a105-99342ff04d2e.png} +0 -0
  23. /kotonebot/kaa/sprites/{52e2b832-7837-47ca-a089-1f1593a99b08.png → 05bfd235-2077-479a-8c43-11fb49316000.png} +0 -0
  24. /kotonebot/kaa/sprites/{c30d08f7-5c07-487a-86c3-122c082bb07b.png → 05f8f996-a38a-45d9-8ff9-720b6c4fd599.png} +0 -0
  25. /kotonebot/kaa/sprites/{9a72b63e-8bd1-47dc-8298-cdf02220201e.png → 05ff5efd-0f76-47ce-bc89-237266bc17c0.png} +0 -0
  26. /kotonebot/kaa/sprites/{172318e0-5e7b-4b61-9a17-6e2e66b27e69.png → 09433024-3dfe-4fcb-9d67-cf442b58f31b.png} +0 -0
  27. /kotonebot/kaa/sprites/{7dd31493-9f3b-4382-a43a-f8eb1c745ad8.png → 0a430873-8c12-4ce2-a5de-ab9790c08344.png} +0 -0
  28. /kotonebot/kaa/sprites/{9f6aef36-f2e5-4208-9748-b6bbdb5546fd.png → 0bab7080-9a37-4c27-9821-8df36d49b678.png} +0 -0
  29. /kotonebot/kaa/sprites/{cc0ac4cf-01fd-48f9-8707-2d6a2aa0ba8c.png → 0bbfb5b0-f0f7-4ad9-86f7-a2adb01a6371.png} +0 -0
  30. /kotonebot/kaa/sprites/{a2ea2e0f-4f92-4769-9bc4-1ee10c43712c.png → 0decaa6a-b9a9-4d9b-829a-0fc1f67538b4.png} +0 -0
  31. /kotonebot/kaa/sprites/{6dcc0bb3-984f-4c92-b0a3-74281d684182.png → 111a03e6-e401-4ad5-b5dc-d5124e8f1ab0.png} +0 -0
  32. /kotonebot/kaa/sprites/{e6e66cdf-69c8-4862-a770-1f81c62f96ac.png → 12e8d3f1-494a-46f5-908f-f621a0c57ec6.png} +0 -0
  33. /kotonebot/kaa/sprites/{5eddc669-dff6-462c-a495-81ddf951429e.png → 13535ecd-bdf5-4ff7-aa2c-6ecb20fe9c06.png} +0 -0
  34. /kotonebot/kaa/sprites/{7d4f53fb-02bc-4139-b32c-3345a5f92a79.png → 157dd58d-e319-4e0c-a37a-638e1a31c60b.png} +0 -0
  35. /kotonebot/kaa/sprites/{3720275d-cbf7-4513-a4a4-09f712b2286a.png → 1a3d18a4-7d91-4182-9e40-e60d73fed365.png} +0 -0
  36. /kotonebot/kaa/sprites/{c287899b-b9a3-4ee2-a8fd-ebda89099b4b.png → 1bfce48a-b151-406e-a6f5-863cb68cbbf2.png} +0 -0
  37. /kotonebot/kaa/sprites/{237636f2-aec0-40be-b7bb-e08607a89307.png → 1f8f8c46-43ec-4449-be9f-2e96da11da1e.png} +0 -0
  38. /kotonebot/kaa/sprites/{ef539419-d100-43d5-83a1-14e65b85d816.png → 1f9165e6-77ee-403e-9b76-99c114527dbb.png} +0 -0
  39. /kotonebot/kaa/sprites/{76c07ba7-afea-405c-806a-7691ce73f83a.png → 22d5a7d5-59a0-4137-b02e-1a7af86d4250.png} +0 -0
  40. /kotonebot/kaa/sprites/{23217053-c549-4ac7-b8c0-3324728e6acd.png → 22ee3f1b-ddcb-48bf-85dd-8423f85e3199.png} +0 -0
  41. /kotonebot/kaa/sprites/{fe031296-8000-4fdc-ab3f-b4aae2af6e5d.png → 24cd42fd-bb3b-4fc6-b40d-d3e3e36fe9f1.png} +0 -0
  42. /kotonebot/kaa/sprites/{7250e776-3195-406c-ac6f-ec7dbed49cbe.png → 2f81e70a-f2af-420f-9b6b-6338c391911f.png} +0 -0
  43. /kotonebot/kaa/sprites/{474ce25b-8a3d-435e-8d7a-ab6566ae61a0.png → 309105d4-073a-47c9-8c5c-d593aa497723.png} +0 -0
  44. /kotonebot/kaa/sprites/{7d968a7f-f4a8-40a0-b9bf-e73ec1f2d7b5.png → 31a52dc8-b7fb-4ff6-a261-eb90a918603c.png} +0 -0
  45. /kotonebot/kaa/sprites/{f6d36222-847e-4300-8f90-c98c7a8f36e3.png → 321b54c8-c69b-4437-931d-655882dabeed.png} +0 -0
  46. /kotonebot/kaa/sprites/{bbfcc1ea-b441-4e81-85d2-52ce3bf4eb62.png → 333fe6d3-0be7-40fb-a2a3-364f98758f2a.png} +0 -0
  47. /kotonebot/kaa/sprites/{c072da5f-bd35-4e8b-8f32-6c5df18c3aea.png → 371a3192-101c-45ef-9da4-2ed389770c0f.png} +0 -0
  48. /kotonebot/kaa/sprites/{b260d390-2b1a-4974-92db-d68ff7b5b8e6.png → 38b8f119-8de1-49bf-8a5f-a44371de4569.png} +0 -0
  49. /kotonebot/kaa/sprites/{19fae7eb-addd-4ea2-99ac-0f9262a4d9d6.png → 43d65b3f-bbae-4e29-a7bf-539379c1b072.png} +0 -0
  50. /kotonebot/kaa/sprites/{22ab93e6-0192-48e1-a85f-73ee8db00395.png → 469006bc-a011-46e4-bcde-992be888456e.png} +0 -0
  51. /kotonebot/kaa/sprites/{608de0a3-ce93-4344-8f9b-3cb3fab5ad12.png → 48c257f8-3583-49f7-b01a-ba7d251086ac.png} +0 -0
  52. /kotonebot/kaa/sprites/{8383a31c-a075-4b5f-b839-cbeb63a7aef3.png → 48d2f007-8c1b-43fc-bd3f-f0b10d2a0c88.png} +0 -0
  53. /kotonebot/kaa/sprites/{dc17dea0-7749-4ecb-bbc0-1a52fb992dcf.png → 4a235eaa-46f1-4f71-b54d-ada0ade44572.png} +0 -0
  54. /kotonebot/kaa/sprites/{b99f0684-8200-4080-9b54-808c4ec12c99.png → 4bd66b38-78d3-4a27-816b-d315039a8bb6.png} +0 -0
  55. /kotonebot/kaa/sprites/{26433c9e-0ea2-4da4-9207-8f3fbad04235.png → 4c72f39e-1182-4479-867f-8207744ee4fd.png} +0 -0
  56. /kotonebot/kaa/sprites/{48a02c33-b7af-4ab5-bda1-3a2ec62a7076.png → 4d6c198a-0e34-4c80-86d1-7789b2082d64.png} +0 -0
  57. /kotonebot/kaa/sprites/{b5009ffd-7e53-41ae-b78d-918ba0e7eda4.png → 4e21f02d-d5e1-49eb-946a-8edc74d0f1f7.png} +0 -0
  58. /kotonebot/kaa/sprites/{5e74dc61-0ad5-4e57-b331-e3d2ed67b6d2.png → 4f58031c-36b9-4baf-bccf-11c05d83bd19.png} +0 -0
  59. /kotonebot/kaa/sprites/{415c45a8-9b71-4e0b-8cd2-f80a0a4aafb7.png → 52620946-b92c-42c7-9fcc-0ff13388fd0d.png} +0 -0
  60. /kotonebot/kaa/sprites/{a1610e9f-93f0-4ef2-b32a-b2effd1673e8.png → 54bb5fcf-be61-4af8-bb19-a3c5113cf9e1.png} +0 -0
  61. /kotonebot/kaa/sprites/{0d1918db-e000-4452-8490-ace623127e76.png → 550fc45d-22c0-4a7c-a324-2c4ff107ab39.png} +0 -0
  62. /kotonebot/kaa/sprites/{bdb09790-f702-4af2-ab67-0b3f05fd93ca.png → 559df9b9-e74d-45af-a300-77d3424e69c6.png} +0 -0
  63. /kotonebot/kaa/sprites/{d3b97b8f-f13a-413d-a097-5c456b8aea0d.png → 56a8c0ca-4659-4de2-9bce-55ce86a40d75.png} +0 -0
  64. /kotonebot/kaa/sprites/{428f770b-e149-417e-bb8a-38c1cba024e1.png → 572077d4-7ee2-449a-b4f0-66239b0d7aff.png} +0 -0
  65. /kotonebot/kaa/sprites/{9d7a7bbb-b48b-458c-9964-963a57e10a7d.png → 5be4f6c7-2baa-42f3-a5a5-99ca0830cc30.png} +0 -0
  66. /kotonebot/kaa/sprites/{370afc82-eea9-4063-afb7-5d5fec075510.png → 5bf00cba-9aab-4ffe-b20b-8f5e74279276.png} +0 -0
  67. /kotonebot/kaa/sprites/{12356f5d-4188-4aa5-abb3-d219ca0167ca.png → 5ca50448-cc21-499a-a685-c5e1c4240c48.png} +0 -0
  68. /kotonebot/kaa/sprites/{9d908390-6f0f-46e6-a8fc-a7dfe23eda18.png → 5edef075-4843-4dc9-840f-ae445cbe0730.png} +0 -0
  69. /kotonebot/kaa/sprites/{51f38e84-56c8-4c80-9a67-35196ef54b89.png → 624555b9-31e3-46a3-8078-55619eaa40b9.png} +0 -0
  70. /kotonebot/kaa/sprites/{14cc953d-0ff6-493f-9478-691b5cbd0d07.png → 645744c4-3bbf-4ea2-8f46-4725fff874b3.png} +0 -0
  71. /kotonebot/kaa/sprites/{08c2352f-0150-453a-aa0e-948dd0deef49.png → 668002b6-805b-467b-a703-203fb75444f4.png} +0 -0
  72. /kotonebot/kaa/sprites/{157cfa99-d40c-48c2-8cf4-70835535522f.png → 67a81c23-4ce4-45e3-bfa8-1136fb14b831.png} +0 -0
  73. /kotonebot/kaa/sprites/{276a66cc-95b1-4f86-b700-afa9c9f18149.png → 695f8d57-b2c9-4a6d-9ae9-1b49ee3eb22a.png} +0 -0
  74. /kotonebot/kaa/sprites/{1df6ff4b-17f8-4ee6-8df0-0b53e26b7f1e.png → 6a7d061e-682b-42c1-97d5-121c52921e8b.png} +0 -0
  75. /kotonebot/kaa/sprites/{b4afb6bd-e049-4b2e-b1ca-26333c7afcb0.png → 6bf5556a-8f4e-41d7-8ab5-d683ad1b47a8.png} +0 -0
  76. /kotonebot/kaa/sprites/{56a70bc5-bd16-493b-b5b6-770f42f13de5.png → 705d9ecf-faf8-40f4-b701-637cec822c1e.png} +0 -0
  77. /kotonebot/kaa/sprites/{e55da40e-5fb5-48e0-91b1-2db0b3b32750.png → 72c1804f-db8c-40fa-bc79-6533f2861a5d.png} +0 -0
  78. /kotonebot/kaa/sprites/{6e338dd7-6834-4e9b-8ac1-afecdff16c43.png → 7344e180-251b-465a-a8cf-974477f7ad44.png} +0 -0
  79. /kotonebot/kaa/sprites/{46ed11a3-f89e-4d5c-b534-da88d38b382b.png → 73af305f-840f-4325-abae-b3519fba672a.png} +0 -0
  80. /kotonebot/kaa/sprites/{7b46a3e5-18d3-45a0-9500-1d7c854a12bb.png → 73f4204e-8281-47cc-9dce-6bb8280c4ce5.png} +0 -0
  81. /kotonebot/kaa/sprites/{382bc600-72f6-433f-809e-9fe2fdb31b32.png → 74521b6f-de5e-4ba8-a3c9-c6ba01070498.png} +0 -0
  82. /kotonebot/kaa/sprites/{8cc764de-f162-40a4-ba6f-40d60eac5633.png → 7736a171-9221-4cda-8288-908997abeff2.png} +0 -0
  83. /kotonebot/kaa/sprites/{55d105dc-c488-47d8-9b95-aba5707cfc2a.png → 79bc56c5-eae6-4389-9116-4a9e182d6bf3.png} +0 -0
  84. /kotonebot/kaa/sprites/{e3cfea3a-3dc4-412b-b226-f9034f5b51f1.png → 7a479871-547e-4098-9cdd-6c9bb9f7449a.png} +0 -0
  85. /kotonebot/kaa/sprites/{6d39d7a2-0b1f-4f49-9ab8-062bca9b5470.png → 7b3c6860-fbbe-48aa-aadf-8062fa88f1fe.png} +0 -0
  86. /kotonebot/kaa/sprites/{f400e1fe-a04d-442b-a6de-a448813443fd.png → 7cea265a-fca5-43d0-b2da-067c8fff4d72.png} +0 -0
  87. /kotonebot/kaa/sprites/{d2732870-dd6b-4b7b-b21e-4ff2a4958b32.png → 7e8164f6-a9e4-4600-b776-77b35a490933.png} +0 -0
  88. /kotonebot/kaa/sprites/{e5922ce7-9aa7-4806-acdd-9c35408a0f37.png → 804a4b05-1ca3-4915-bf23-a66ccdc34404.png} +0 -0
  89. /kotonebot/kaa/sprites/{e508161a-e595-4daf-a364-625aaf67e481.png → 80fb515c-4323-422d-a24c-80a3bf702f1d.png} +0 -0
  90. /kotonebot/kaa/sprites/{685a7a90-8196-4a6a-a67a-4e7078965982.png → 826bf80a-112e-4356-9111-4b7e692ccc82.png} +0 -0
  91. /kotonebot/kaa/sprites/{3e10014e-2063-424c-aeda-df985d351c12.png → 82a5e224-a161-43d4-8e15-2946480336dd.png} +0 -0
  92. /kotonebot/kaa/sprites/{d0c085fa-3089-4adf-979c-d4b274b32c3b.png → 869b1771-b2ce-4872-ab75-2157c47c5b13.png} +0 -0
  93. /kotonebot/kaa/sprites/{cecd2638-070f-4710-9142-2dc492660241.png → 89c0e675-3fd4-456a-8ae7-3bfb248b7281.png} +0 -0
  94. /kotonebot/kaa/sprites/{99c36126-0173-49f3-a6b8-819bf9bd9306.png → 8e8a0b57-0231-4ed6-958e-3196f7c9ca7b.png} +0 -0
  95. /kotonebot/kaa/sprites/{8da0b45e-3d90-40f0-9781-c1ff4cd0e060.png → 90a9c819-ee6b-4b3e-a0e4-ce484c6e413d.png} +0 -0
  96. /kotonebot/kaa/sprites/{60e43a33-18ee-45f1-bd9a-57bb6539611b.png → 910d307b-6461-4950-badb-509975d0b797.png} +0 -0
  97. /kotonebot/kaa/sprites/{a1a03d83-6a3b-481a-a807-931f2b0f7cd2.png → 92b7d830-3db5-434e-b156-0ac855db480d.png} +0 -0
  98. /kotonebot/kaa/sprites/{86501f18-e5fd-4a66-a360-20e34935f1a9.png → 96cf0633-6531-499b-b1cc-6670ab710293.png} +0 -0
  99. /kotonebot/kaa/sprites/{74db3d1c-d6be-4d1f-92be-9bb3ffad7f51.png → 994aa6a6-0189-4a79-8125-56136973b581.png} +0 -0
  100. /kotonebot/kaa/sprites/{465d4e1a-c5f9-41b7-aa31-ce26d5c69c45.png → 9bb1a400-935a-4c5e-838b-fca502c49aba.png} +0 -0
  101. /kotonebot/kaa/sprites/{1e9e795c-5dc1-4851-8d49-86181b9f4efe.png → 9c1fa1d4-2ae5-4093-abaa-cebb51135721.png} +0 -0
  102. /kotonebot/kaa/sprites/{8e04cb5c-ce45-49d9-81a9-2e5f717d3eb2.png → a00fcf77-2800-4f7d-993d-4636b36045bb.png} +0 -0
  103. /kotonebot/kaa/sprites/{863550ee-e9b8-4aa2-8ebb-e906b09dde3b.png → a105d17d-d44c-4798-aeff-70808c91cb47.png} +0 -0
  104. /kotonebot/kaa/sprites/{eb229797-bffc-4a48-96de-85480af1608a.png → a33ae1c3-ac69-4783-977e-9f0f1b1a2f8d.png} +0 -0
  105. /kotonebot/kaa/sprites/{3851e552-fd41-4a15-a6b6-9636c773f67a.png → a3c12040-2b11-4038-b830-215fb7b6f359.png} +0 -0
  106. /kotonebot/kaa/sprites/{1d6d5160-9525-42bf-a8d4-43c347d213eb.png → a82e06fb-a02e-4be5-a7b4-4d2758914fcf.png} +0 -0
  107. /kotonebot/kaa/sprites/{f4a1201f-9305-4ec5-8962-2bef0144ab46.png → ad784a29-f0e2-4037-976b-45143db8441c.png} +0 -0
  108. /kotonebot/kaa/sprites/{4ddc656f-ef7e-4580-ad12-9e382ea76e4f.png → ad8ee599-88a8-429c-8982-99086e552dcc.png} +0 -0
  109. /kotonebot/kaa/sprites/{934e5383-b63c-472e-afdb-d184c92bdfe3.png → afa0f85f-dcb7-48a1-a1ae-624456b9b65c.png} +0 -0
  110. /kotonebot/kaa/sprites/{de0b3d75-7dc8-4433-a275-2584e9d7ed0b.png → b1d1dfab-51f5-4ae9-b718-cdf46774c0ff.png} +0 -0
  111. /kotonebot/kaa/sprites/{872c37e7-e596-4449-86f4-5ba65836a7a7.png → b1e88fda-434a-4d06-8891-883a7beafa12.png} +0 -0
  112. /kotonebot/kaa/sprites/{51b836ff-5f2c-4612-85f1-9db74761f300.png → b2f7a430-5777-4861-8435-5419394e5ee8.png} +0 -0
  113. /kotonebot/kaa/sprites/{4b121018-f5c8-4c31-a5d9-48947982b191.png → b3d1f8d4-1393-4206-b78e-a5495d8fb930.png} +0 -0
  114. /kotonebot/kaa/sprites/{cd53bad6-81fa-4e15-8fe7-5a992367bf90.png → b3e72de2-e103-49a3-b0f2-8593cff87c4e.png} +0 -0
  115. /kotonebot/kaa/sprites/{8778f70d-6bb8-4378-aed7-d77c798ab032.png → b44f5e5b-e999-4427-8a9f-f76c6485f4a5.png} +0 -0
  116. /kotonebot/kaa/sprites/{9b798f35-e745-4964-931d-3e0ae811174d.png → b604e25d-680a-4e02-a012-2e593b5bc276.png} +0 -0
  117. /kotonebot/kaa/sprites/{2ef87b7f-d69e-4da2-878f-1cc35e48b15c.png → ba955365-1328-4018-83a2-bfe818f8f172.png} +0 -0
  118. /kotonebot/kaa/sprites/{5a4a763f-b69b-4405-994d-470a78476f67.png → c0fc7de5-b842-4c70-9cf2-89d833bfe7a6.png} +0 -0
  119. /kotonebot/kaa/sprites/{4ffd7c97-86dd-4171-92e7-8e8e83e8f394.png → c1ad996a-925e-41b5-b26c-d48b8ded21d2.png} +0 -0
  120. /kotonebot/kaa/sprites/{e98037f8-3b4a-4de8-adc1-ca0f736b6c98.png → c1b1125f-542b-4e63-9c86-5d2e35a89a10.png} +0 -0
  121. /kotonebot/kaa/sprites/{593f4c04-4ca4-4bb0-8fea-ad3af32316f7.png → c2667677-cbff-4dd4-a401-e0963e7224f4.png} +0 -0
  122. /kotonebot/kaa/sprites/{ddb2e9ee-e16a-4745-8598-b3f9c2f011be.png → c4f28132-4aba-40ba-be6c-b1a31d014635.png} +0 -0
  123. /kotonebot/kaa/sprites/{ced345fa-b375-457d-8b72-802424512e6c.png → c7aa3f89-8a5e-4685-9297-4fc892bfdd81.png} +0 -0
  124. /kotonebot/kaa/sprites/{c94488b2-0ff0-4467-bbb0-405d3a2c55a3.png → cc829886-23e8-4d47-b4c4-37ca20381180.png} +0 -0
  125. /kotonebot/kaa/sprites/{34ec068a-d6fd-47ac-bd2f-0c31f93c19f3.png → cd4cbd7b-df80-45bb-a053-cc333a806934.png} +0 -0
  126. /kotonebot/kaa/sprites/{9e74a9e6-6ea5-4551-9578-8e561195bd3d.png → cd8d3d55-f102-419e-a6fd-2ad5ecc4fd2e.png} +0 -0
  127. /kotonebot/kaa/sprites/{86bcda3a-c7a6-4abf-ae4c-968788f3c667.png → d22ca9e0-001d-43d6-a557-1c76c5a27c81.png} +0 -0
  128. /kotonebot/kaa/sprites/{267fcd93-6a5c-4954-a06b-e97f327e9141.png → d58d9987-b1ca-4669-a9a6-9a0fd1847fa6.png} +0 -0
  129. /kotonebot/kaa/sprites/{37f421f8-f615-43d1-a10f-f9a915a940d1.png → d747239f-7620-4f23-9ac7-cf2d34889266.png} +0 -0
  130. /kotonebot/kaa/sprites/{63bfee9f-546e-4c3c-a82f-c2707bc62b90.png → d7f604a6-c663-44db-b1d3-c9792eb3daa4.png} +0 -0
  131. /kotonebot/kaa/sprites/{a69febc4-2d01-4628-be92-29b421604c4d.png → d8136469-6d73-4f82-a79c-fee83c3e93a8.png} +0 -0
  132. /kotonebot/kaa/sprites/{4b87be27-868a-40fb-b7e4-67c963c6c4b2.png → da3e7cee-d77b-4e62-b703-ed257706dd39.png} +0 -0
  133. /kotonebot/kaa/sprites/{37e3a757-bcbc-4a37-bbf9-a38162a8627e.png → db94ffb7-a09d-4a51-b420-b930851c9db4.png} +0 -0
  134. /kotonebot/kaa/sprites/{72b7124a-baf2-4d60-9553-2634370a6d49.png → de709296-e411-465f-86fc-5daf5ca83cef.png} +0 -0
  135. /kotonebot/kaa/sprites/{9ce49f31-6b3a-4bc7-a9c8-9330d6f650f7.png → e2fae2a4-bb19-4f49-b382-47e504ec26d3.png} +0 -0
  136. /kotonebot/kaa/sprites/{aad29ac0-b9ad-4c38-93f5-e8036ad7b96b.png → e41bb5df-164d-4760-9db6-d5d5d763bb5f.png} +0 -0
  137. /kotonebot/kaa/sprites/{09a01092-0d32-4894-a47e-9983b39753df.png → e5d15c50-45ee-4de9-8b97-4630cbd8f01a.png} +0 -0
  138. /kotonebot/kaa/sprites/{f3b4bb3b-f8d6-4ed0-8bde-0d3322bd8391.png → e7022542-4317-4a61-8098-f3f733d8400e.png} +0 -0
  139. /kotonebot/kaa/sprites/{a5d05106-5a60-414c-972d-a886664abde4.png → e866d8b1-4f61-45bf-8170-5229f53c047a.png} +0 -0
  140. /kotonebot/kaa/sprites/{7c65fc91-602b-4d1b-82f9-c9b561a55d9b.png → ecd44a4a-e1ca-4a86-ae0d-2306a672613f.png} +0 -0
  141. /kotonebot/kaa/sprites/{588f3405-4110-48dd-99ec-f89c004cf02e.png → ed5d2bf3-405c-4165-88d0-9f8a4be968c6.png} +0 -0
  142. /kotonebot/kaa/sprites/{a829f038-5421-4cc4-a494-105a973351e2.png → ef39804e-8d2d-40f6-8d13-bd2877d1353a.png} +0 -0
  143. /kotonebot/kaa/sprites/{263708c5-0177-4c6a-8df3-611ec314fa56.png → f0786a26-81b5-4e76-b577-db70ab3fab50.png} +0 -0
  144. /kotonebot/kaa/sprites/{aa8c4533-bd58-496e-a460-6fa47f7ded83.png → f65a4495-f044-44de-bf0d-c869e637d5d3.png} +0 -0
  145. /kotonebot/kaa/sprites/{465f1030-e538-4b22-a6f7-0087287b2e12.png → f74fc514-61f1-4068-bdf4-754fcaf8ac89.png} +0 -0
  146. /kotonebot/kaa/sprites/{7f0783fe-89d9-4405-b7a3-6334ba543826.png → f8cbb089-a63e-4e40-9238-26d14da2c459.png} +0 -0
  147. /kotonebot/kaa/sprites/{3a0e917b-f419-4398-8638-77f696d47cd4.png → f9b2f64d-f829-4b13-9704-c5f00fb956be.png} +0 -0
  148. /kotonebot/kaa/sprites/{c4fed66b-e195-4288-8b1f-ef4b0ef35174.png → fb927b92-7a82-4869-8c61-581d49cd7201.png} +0 -0
  149. /kotonebot/kaa/sprites/{e9e399f7-4e2f-4392-bb8f-850c4a272dfa.png → fbd816df-7ae6-40a4-b4d4-5708f5ba4a7c.png} +0 -0
  150. /kotonebot/kaa/sprites/{2e0f97d4-ce0b-4930-addd-cbdaedffc918.png → fd610de1-b023-4747-8c1b-72f89b1c5647.png} +0 -0
  151. /kotonebot/kaa/sprites/{e0a5c772-49d3-468a-bcf5-0e3f24365253.png → fdfecda8-2fe0-487e-b5fe-6358274bb9ff.png} +0 -0
  152. /kotonebot/kaa/sprites/{f4b226eb-ed9e-4e5e-9ba0-1b777e401aa3.png → ff77d221-8444-4d0f-8c93-0223a97e2a98.png} +0 -0
  153. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.8.0.dist-info}/WHEEL +0 -0
  154. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.8.0.dist-info}/entry_points.txt +0 -0
  155. {ksaa-2025.5.23.3.dist-info → ksaa-2025.6.8.0.dist-info}/top_level.txt +0 -0
kotonebot/backend/bot.py CHANGED
@@ -32,7 +32,7 @@ class RunStatus:
32
32
  callstack: list[Task | Action] = field(default_factory=list)
33
33
 
34
34
  def interrupt(self):
35
- vars.interrupted.set()
35
+ vars.flow.request_interrupt()
36
36
 
37
37
  # Modified from https://stackoverflow.com/questions/70982565/how-do-i-make-an-event-listener-with-decorators-in-python
38
38
  Params = ParamSpec('Params')
@@ -158,7 +158,7 @@ class KotoneBot:
158
158
  d = self._on_create_device()
159
159
  init_context(config_path=self.config_path, config_type=self.config_type, target_device=d)
160
160
  self._on_after_init_context()
161
- vars.interrupted.clear()
161
+ vars.flow.clear_interrupt()
162
162
 
163
163
  if by_priority:
164
164
  tasks = sorted(tasks, key=lambda x: x.priority, reverse=True)
@@ -180,7 +180,7 @@ class KotoneBot:
180
180
  logger.exception('Keyboard interrupt detected.')
181
181
  for task1 in tasks[tasks.index(task):]:
182
182
  self.events.task_status_changed.trigger(task1, 'cancelled')
183
- vars.interrupted.clear()
183
+ vars.flow.clear_interrupt()
184
184
  break
185
185
  # 其他错误
186
186
  except Exception as e:
@@ -3,6 +3,7 @@ import re
3
3
  import time
4
4
  import logging
5
5
  import warnings
6
+ import threading
6
7
  from datetime import datetime
7
8
  from threading import Event
8
9
  from typing import (
@@ -25,6 +26,7 @@ import cv2
25
26
  from cv2.typing import MatLike
26
27
 
27
28
  from kotonebot.client.device import Device
29
+ from kotonebot.backend.flow_controller import FlowController
28
30
  import kotonebot.backend.image as raw_image
29
31
  from kotonebot.backend.image import (
30
32
  TemplateMatchResult,
@@ -126,8 +128,7 @@ def interruptible(func: Callable[P, T]) -> Callable[P, T]:
126
128
  """
127
129
  def _decorator(*args: P.args, **kwargs: P.kwargs) -> T:
128
130
  global vars
129
- if vars.interrupted.is_set():
130
- raise KeyboardInterrupt("User requested interrupt.")
131
+ vars.flow.check()
131
132
  return func(*args, **kwargs)
132
133
  return _decorator
133
134
 
@@ -145,15 +146,13 @@ def interruptible_class(cls: Type[T]) -> Type[T]:
145
146
 
146
147
  def sleep(seconds: float, /):
147
148
  """
148
- 可中断的 sleep 函数。
149
+ 可中断和可暂停的 sleep 函数。
149
150
 
150
151
  建议使用本函数代替 `time.sleep()`,
151
- 这样能以最快速度响应用户请求中断。
152
+ 这样能以最快速度响应用户请求中断和暂停。
152
153
  """
153
154
  global vars
154
- vars.interrupted.wait(timeout=seconds)
155
- if vars.interrupted.is_set():
156
- raise KeyboardInterrupt("User requested interrupt.")
155
+ vars.flow.sleep(seconds)
157
156
 
158
157
  def warn_manual_screenshot_mode(name: str, alternative: str):
159
158
  """
@@ -175,8 +174,8 @@ def is_manual_screenshot_mode() -> bool:
175
174
  class ContextGlobalVars:
176
175
  def __init__(self):
177
176
  self.__vars = dict[str, Any]()
178
- self.interrupted: Event = Event()
179
- """用户请求中断事件"""
177
+ self.flow: FlowController = FlowController()
178
+ """流程控制器,负责停止、暂停、恢复等操作"""
180
179
 
181
180
  def __getitem__(self, key: str) -> Any:
182
181
  return self.__vars[key]
@@ -198,6 +197,17 @@ class ContextGlobalVars:
198
197
 
199
198
  def clear(self):
200
199
  self.__vars.clear()
200
+ self.flow.reset() # 重置流程控制器
201
+
202
+ def check_flow_control():
203
+ """
204
+ 统一的流程控制检查函数。
205
+
206
+ 检查用户是否请求中断或暂停,如果是则相应处理:
207
+ - 如果请求中断,抛出 KeyboardInterrupt 异常
208
+ - 如果请求暂停,等待直到恢复
209
+ """
210
+ vars.flow.check()
201
211
 
202
212
  class ContextStackVars:
203
213
  stack: list['ContextStackVars'] = []
@@ -716,6 +726,7 @@ class ContextDevice(Device):
716
726
  """
717
727
  截图。返回截图数据,同时更新当前上下文的截图数据。
718
728
  """
729
+ check_flow_control()
719
730
  global next_wait, last_screenshot_time, next_wait_time
720
731
  current = ContextStackVars.ensure_current()
721
732
  if force:
@@ -950,5 +961,4 @@ def manual_context(screenshot_mode: ScreenshotMode = 'auto') -> ManualContextMan
950
961
  默认情况下,Context* 类仅允许在 @task/@action 函数中使用。
951
962
  如果想要在其他地方使用,使用此函数手动创建一个上下文。
952
963
  """
953
- return ManualContextManager(screenshot_mode)
954
-
964
+ return ManualContextManager(screenshot_mode)
@@ -115,7 +115,7 @@ async def run_code(request: RunCodeRequest):
115
115
  except KeyboardInterrupt as e:
116
116
  result = {"status": "error", "result": stdout.getvalue(), "message": str(e), "traceback": traceback.format_exc()}
117
117
  finally:
118
- context_vars.interrupted.clear()
118
+ context_vars.flow.clear_interrupt()
119
119
  event.set()
120
120
  threading.Thread(target=_runner, daemon=True).start()
121
121
  await event.wait()
@@ -124,8 +124,8 @@ async def run_code(request: RunCodeRequest):
124
124
  @app.get("/api/code/stop")
125
125
  async def stop_code():
126
126
  from kotonebot.backend.context import vars
127
- vars.interrupted.set()
128
- while vars.interrupted.is_set():
127
+ vars.flow.request_interrupt()
128
+ while vars.flow.is_interrupted:
129
129
  await asyncio.sleep(0.1)
130
130
  return {"status": "ok"}
131
131
 
@@ -0,0 +1,195 @@
1
+ import time
2
+ import logging
3
+ import threading
4
+ from typing import Literal
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ class FlowController:
9
+ """
10
+ 一个用于控制任务执行流程(如停止、暂停、恢复)的类。
11
+
12
+ 这个类是线程安全的,提供了以下功能:
13
+
14
+ * 停止任务执行(通过中断信号)
15
+ * 暂停/恢复任务执行
16
+ * 可中断和可暂停的 sleep 功能
17
+ * 流程状态检查
18
+
19
+ 使用方法::
20
+
21
+ controller = FlowController()
22
+
23
+ # 在任务的关键路径上调用检查
24
+ controller.check()
25
+
26
+ # 使用可控制的 sleep
27
+ controller.sleep(1.0)
28
+
29
+ # 外部控制
30
+ controller.request_pause() # 暂停
31
+ controller.request_resume() # 恢复
32
+ controller.request_stop() # 停止
33
+ """
34
+
35
+ def __init__(self):
36
+ self.interrupt_event: threading.Event = threading.Event()
37
+ """中断事件,用于停止任务"""
38
+
39
+ self.paused: bool = False
40
+ """暂停标志"""
41
+
42
+ self.pause_condition: threading.Condition = threading.Condition()
43
+ """暂停条件变量,用于线程间同步"""
44
+
45
+ def check(self) -> None:
46
+ """
47
+ 检查当前流程状态。
48
+
49
+ 如果收到停止请求,则抛出 KeyboardInterrupt 异常。
50
+ 如果收到暂停请求,则阻塞直到恢复。
51
+
52
+ 这是核心的检查点方法,应在任务的关键路径上(如循环或等待前)调用。
53
+
54
+ :raises KeyboardInterrupt: 当收到停止请求时
55
+ """
56
+ # 优先检查中断信号
57
+ if self.interrupt_event.is_set():
58
+ raise KeyboardInterrupt("User requested interrupt.")
59
+
60
+ # 检查暂停状态
61
+ with self.pause_condition:
62
+ while self.paused:
63
+ self.pause_condition.wait()
64
+
65
+ def sleep(self, seconds: float) -> None:
66
+ """
67
+ 一个可被中断和暂停的 sleep 方法。
68
+
69
+ 与标准的 time.sleep() 不同,这个方法会响应停止和暂停请求。
70
+ 在暂停状态下,计时器会暂停,恢复后继续计时。
71
+
72
+ :param seconds: 睡眠时间(秒)
73
+ :raises KeyboardInterrupt: 当收到停止请求时
74
+ """
75
+ with self.pause_condition:
76
+ end_time = time.time() + seconds
77
+ while True:
78
+ self.check() # 每次循环都检查状态
79
+ remaining = end_time - time.time()
80
+ if remaining <= 0:
81
+ break
82
+ # 等待指定时间或直到被唤醒
83
+ self.pause_condition.wait(timeout=remaining)
84
+
85
+ # 结束后再次检查状态
86
+ self.check()
87
+
88
+ def request_interrupt(self) -> None:
89
+ """
90
+ 请求停止任务。
91
+
92
+ 设置中断信号,所有正在执行的任务将在下一个检查点停止。
93
+ 停止的优先级高于暂停。
94
+ """
95
+ logger.info('Interrupt requested.')
96
+ self.interrupt_event.set()
97
+
98
+ def request_pause(self) -> None:
99
+ """
100
+ 请求暂停任务。
101
+
102
+ 设置暂停标志,所有正在执行的任务将在下一个检查点暂停。
103
+ 如果任务已经暂停,此操作无效果。
104
+ """
105
+ with self.pause_condition:
106
+ if not self.paused:
107
+ logger.info('Pause requested.')
108
+ self.paused = True
109
+
110
+ def request_resume(self) -> None:
111
+ """
112
+ 请求恢复任务。
113
+
114
+ 清除暂停标志并通知所有等待的线程恢复执行。
115
+ 如果任务没有暂停,此操作无效果。
116
+ """
117
+ with self.pause_condition:
118
+ if self.paused:
119
+ logger.info('Resume requested.')
120
+ self.paused = False
121
+ self.pause_condition.notify_all()
122
+
123
+ def toggle_pause(self) -> bool:
124
+ """
125
+ 切换暂停/恢复状态。
126
+
127
+ :returns: 操作后的暂停状态。True 表示已暂停,False 表示已恢复。
128
+ """
129
+ with self.pause_condition:
130
+ logger.info('Pause toggled.')
131
+ if self.paused:
132
+ self.paused = False
133
+ self.pause_condition.notify_all()
134
+ return False
135
+ else:
136
+ self.paused = True
137
+ return True
138
+
139
+ def clear_interrupt(self) -> None:
140
+ """
141
+ 清除中断信号。
142
+
143
+ 用于任务正常结束或重启时重置状态。
144
+ 通常在开始新任务前调用。
145
+ """
146
+ self.interrupt_event.clear()
147
+ logger.info('Interrupt cleared.')
148
+
149
+ def reset(self) -> None:
150
+ """
151
+ 重置流程控制器到初始状态。
152
+
153
+ 清除所有信号和状态,相当于重新创建一个新的控制器。
154
+ """
155
+ self.interrupt_event.clear()
156
+ with self.pause_condition:
157
+ if self.paused:
158
+ self.paused = False
159
+ self.pause_condition.notify_all()
160
+ logger.info('FlowController reset.')
161
+
162
+ @property
163
+ def is_interrupted(self) -> bool:
164
+ """
165
+ 检查是否收到中断请求。
166
+
167
+ :returns: True 表示已收到中断请求
168
+ """
169
+ return self.interrupt_event.is_set()
170
+
171
+ @property
172
+ def is_paused(self) -> bool:
173
+ """
174
+ 检查是否处于暂停状态。
175
+
176
+ :returns: True 表示当前处于暂停状态
177
+ """
178
+ return self.paused
179
+
180
+ @property
181
+ def status(self) -> Literal['running', 'paused', 'interrupted']:
182
+ """
183
+ 获取当前状态的字符串描述。
184
+
185
+ :returns: 状态描述,可能的值:'running', 'paused', 'interrupted'
186
+ """
187
+ if self.is_interrupted:
188
+ return 'interrupted'
189
+ elif self.is_paused:
190
+ return 'paused'
191
+ else:
192
+ return 'running'
193
+
194
+ def __repr__(self) -> str:
195
+ return f"FlowController(status='{self.status}')"
@@ -7,7 +7,7 @@ import cv2
7
7
  import win32ui
8
8
  import win32gui
9
9
  import numpy as np
10
- from ahk import AHK
10
+ from ahk import AHK, MsgBoxIcon
11
11
  from cv2.typing import MatLike
12
12
 
13
13
  from ..device import Device
@@ -19,14 +19,26 @@ class WindowsImpl(Touchable, Screenshotable):
19
19
  # TODO: 硬编码路径
20
20
  self.ahk = AHK(executable_path=str(resources.files('kaa.res.bin') / 'AutoHotkey.exe'))
21
21
  self.device = device
22
- self.emergency = False
23
22
 
24
23
  # 设置 DPI aware,否则高缩放显示器上返回的坐标会错误
25
24
  windll.user32.SetProcessDPIAware()
26
- def toggle_emergency():
27
- self.emergency = True
28
- self.ahk.msg_box('已启用紧急暂停模式')
29
- self.ahk.add_hotkey('^F4', toggle_emergency)
25
+ # TODO: 这个应该移动到其他地方去
26
+ def _stop():
27
+ from kotonebot.backend.context.context import vars
28
+ vars.flow.request_interrupt()
29
+ self.ahk.msg_box('任务已停止。', title='琴音小助手', icon=MsgBoxIcon.EXCLAMATION)
30
+
31
+ def _toggle_pause():
32
+ from kotonebot.backend.context.context import vars
33
+ if vars.flow.is_paused:
34
+ self.ahk.msg_box('任务即将恢复。\n关闭此消息框后将会继续执行', title='琴音小助手', icon=MsgBoxIcon.EXCLAMATION)
35
+ vars.flow.request_resume()
36
+ else:
37
+ vars.flow.request_pause()
38
+ self.ahk.msg_box('任务已暂停。\n关闭此消息框后再按一次快捷键恢复执行。', title='琴音小助手', icon=MsgBoxIcon.EXCLAMATION)
39
+
40
+ self.ahk.add_hotkey('^F4', _toggle_pause) # Ctrl+F4 暂停/恢复
41
+ self.ahk.add_hotkey('^F3', _stop) # Ctrl+F3 停止
30
42
  self.ahk.start_hotkeys()
31
43
  # 将点击坐标设置为相对 Client
32
44
  self.ahk.set_coord_mode('Mouse', 'Client')
@@ -60,11 +72,6 @@ class WindowsImpl(Touchable, Screenshotable):
60
72
  """将 Client 区域坐标转换为屏幕坐标"""
61
73
  return win32gui.ClientToScreen(hwnd, (x, y))
62
74
 
63
- def __wait_not_emergency(self):
64
- from time import sleep # TODO: 改为 kotonebot.backend.context.sleep
65
- while self.emergency:
66
- sleep(0.2)
67
-
68
75
  def screenshot(self) -> MatLike:
69
76
  if not self.ahk.win_is_active('gakumas'):
70
77
  self.ahk.win_activate('gakumas')
@@ -133,7 +140,6 @@ class WindowsImpl(Touchable, Screenshotable):
133
140
  return 'portrait'
134
141
 
135
142
  def click(self, x: int, y: int) -> None:
136
- self.__wait_not_emergency()
137
143
  # x, y = self.__client_to_screen(self.hwnd, x, y)
138
144
  # (0, 0) 很可能会点到窗口边框上
139
145
  if x == 0:
@@ -146,7 +152,6 @@ class WindowsImpl(Touchable, Screenshotable):
146
152
  self.ahk.click(x, y)
147
153
 
148
154
  def swipe(self, x1: int, y1: int, x2: int, y2: int, duration: float | None = None) -> None:
149
- self.__wait_not_emergency()
150
155
  if not self.ahk.win_is_active('gakumas'):
151
156
  self.ahk.win_activate('gakumas')
152
157
  x1, y1 = int(x1 / self.scale_ratio), int(y1 / self.scale_ratio)
kotonebot/kaa/common.py CHANGED
@@ -425,6 +425,20 @@ class StartGameConfig(ConfigBaseModel):
425
425
 
426
426
  kuyo_package_name: str = 'org.kuyo.game'
427
427
  """Kuyo包名"""
428
+
429
+ disable_gakumas_localify: bool = False
430
+ """
431
+ 自动检测并禁用 Gakumas Localify 汉化插件。
432
+
433
+ (目前仅对 DMM 版有效。)
434
+ """
435
+
436
+ dmm_game_path: str | None = None
437
+ """
438
+ DMM 版游戏路径。若不填写,会自动检测。
439
+
440
+ 例:`F:\\Games\\gakumas\\gakumas.exe`
441
+ """
428
442
 
429
443
  class EndGameConfig(ConfigBaseModel):
430
444
  exit_kaa: bool = False
@@ -439,6 +453,13 @@ class EndGameConfig(ConfigBaseModel):
439
453
  """关闭系统"""
440
454
  hibernate: bool = False
441
455
  """休眠系统"""
456
+ restore_gakumas_localify: bool = False
457
+ """
458
+ 恢复 Gakumas Localify 汉化插件状态至启动前。通常与
459
+ `disable_gakumas_localify` 配对使用。
460
+
461
+ (目前仅对 DMM 版有效。)
462
+ """
442
463
 
443
464
  class BaseConfig(ConfigBaseModel):
444
465
  purchase: PurchaseConfig = PurchaseConfig()