bcsfe 3.3.0__tar.gz → 3.4.0__tar.gz

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 (235) hide show
  1. {bcsfe-3.3.0/src/bcsfe.egg-info → bcsfe-3.4.0}/PKG-INFO +6 -4
  2. {bcsfe-3.3.0 → bcsfe-3.4.0}/README.md +5 -3
  3. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/__init__.py +1 -1
  4. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/__main__.py +16 -2
  5. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/cat_editor.py +6 -4
  6. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/storage.py +31 -2
  7. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/feature_handler.py +36 -40
  8. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/main.py +2 -4
  9. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/recent_saves.py +5 -2
  10. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/save_management.py +13 -8
  11. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/server_cli.py +7 -1
  12. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/__init__.py +20 -0
  13. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/gatya.py +1 -1
  14. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/config.py +1 -1
  15. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/git_handler.py +2 -4
  16. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/path.py +47 -7
  17. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/root_handler.py +1 -1
  18. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/save.py +10 -3
  19. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/locale_handler.py +1 -1
  20. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/log.py +11 -18
  21. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/game_data_getter.py +6 -5
  22. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/server_handler.py +8 -6
  23. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/theme_handler.py +3 -11
  24. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/save.properties +4 -3
  25. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/cats.properties +2 -0
  26. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/special_skills.properties +1 -1
  27. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/config.properties +95 -0
  28. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/files.properties +9 -0
  29. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/input.properties +31 -0
  30. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/locale.properties +33 -0
  31. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/main.properties +111 -0
  32. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/save.properties +117 -0
  33. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/server.properties +58 -0
  34. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/theme.properties +24 -0
  35. bcsfe-3.4.0/src/bcsfe/files/locales/tw/core/updater.properties +19 -0
  36. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/bannable_items.properties +30 -0
  37. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/cats.properties +160 -0
  38. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/enemy.properties +17 -0
  39. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/fixes.properties +13 -0
  40. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gambling.properties +3 -0
  41. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gamototo.properties +56 -0
  42. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gatya.properties +8 -0
  43. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/gold_pass.properties +6 -0
  44. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/items.properties +64 -0
  45. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/map.properties +178 -0
  46. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/medals.properties +8 -0
  47. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/missions.properties +7 -0
  48. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/playtime.properties +7 -0
  49. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/scheme_items.properties +6 -0
  50. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/special_skills.properties +10 -0
  51. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/talent_orbs.properties +26 -0
  52. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/treasures.properties +24 -0
  53. bcsfe-3.4.0/src/bcsfe/files/locales/tw/edits/user_rank.properties +9 -0
  54. bcsfe-3.4.0/src/bcsfe/files/locales/tw/metadata.json +4 -0
  55. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/config.properties +95 -0
  56. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/core/files.properties +1 -1
  57. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/input.properties +33 -0
  58. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/locale.properties +118 -0
  59. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/main.properties +75 -0
  60. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/save.properties +84 -0
  61. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/server.properties +31 -0
  62. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/theme.properties +24 -0
  63. bcsfe-3.4.0/src/bcsfe/files/locales/vi/core/updater.properties +20 -0
  64. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/bannable_items.properties +31 -0
  65. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/cats.properties +154 -0
  66. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/enemy.properties +18 -0
  67. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/fixes.properties +13 -0
  68. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/edits/gambling.properties +4 -3
  69. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/gamototo.properties +56 -0
  70. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/gatya.properties +9 -0
  71. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/gold_pass.properties +7 -0
  72. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/items.properties +65 -0
  73. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/map.properties +177 -0
  74. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/medals.properties +9 -0
  75. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/missions.properties +8 -0
  76. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/playtime.properties +8 -0
  77. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/edits/scheme_items.properties +1 -1
  78. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/edits/special_skills.properties +3 -3
  79. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +24 -0
  80. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/treasures.properties +25 -0
  81. bcsfe-3.4.0/src/bcsfe/files/locales/vi/edits/user_rank.properties +10 -0
  82. {bcsfe-3.3.0 → bcsfe-3.4.0/src/bcsfe.egg-info}/PKG-INFO +6 -4
  83. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe.egg-info/SOURCES.txt +28 -0
  84. {bcsfe-3.3.0 → bcsfe-3.4.0}/tests/test_parse.py +0 -3
  85. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/config.properties +0 -97
  86. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/input.properties +0 -32
  87. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/locale.properties +0 -33
  88. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/main.properties +0 -113
  89. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/save.properties +0 -107
  90. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/server.properties +0 -51
  91. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/theme.properties +0 -25
  92. bcsfe-3.3.0/src/bcsfe/files/locales/vi/core/updater.properties +0 -20
  93. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/bannable_items.properties +0 -31
  94. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/cats.properties +0 -166
  95. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/enemy.properties +0 -18
  96. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/fixes.properties +0 -14
  97. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/gamototo.properties +0 -55
  98. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/gatya.properties +0 -9
  99. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/gold_pass.properties +0 -7
  100. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/items.properties +0 -56
  101. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/map.properties +0 -158
  102. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/medals.properties +0 -9
  103. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/missions.properties +0 -8
  104. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/playtime.properties +0 -8
  105. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/talent_orbs.properties +0 -25
  106. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/treasures.properties +0 -25
  107. bcsfe-3.3.0/src/bcsfe/files/locales/vi/edits/user_rank.properties +0 -10
  108. {bcsfe-3.3.0 → bcsfe-3.4.0}/LICENSE +0 -0
  109. {bcsfe-3.3.0 → bcsfe-3.4.0}/MANIFEST.in +0 -0
  110. {bcsfe-3.3.0 → bcsfe-3.4.0}/pyproject.toml +0 -0
  111. {bcsfe-3.3.0 → bcsfe-3.4.0}/setup.cfg +0 -0
  112. {bcsfe-3.3.0 → bcsfe-3.4.0}/setup.py +0 -0
  113. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/__init__.py +0 -0
  114. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/color.py +0 -0
  115. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/dialog_creator.py +0 -0
  116. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/__init__.py +0 -0
  117. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/aku_realm.py +0 -0
  118. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/basic_items.py +0 -0
  119. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/clear_tutorial.py +0 -0
  120. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/enemy_editor.py +0 -0
  121. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/event_tickets.py +0 -0
  122. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/fixes.py +0 -0
  123. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/map.py +0 -0
  124. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/max_all.py +0 -0
  125. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/edits/rare_ticket_trade.py +0 -0
  126. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/cli/file_dialog.py +0 -0
  127. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/country_code.py +0 -0
  128. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/crypto.py +0 -0
  129. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/__init__.py +0 -0
  130. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/__init__.py +0 -0
  131. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/battle_items.py +0 -0
  132. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/cleared_slots.py +0 -0
  133. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/enemy.py +0 -0
  134. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/battle/slots.py +0 -0
  135. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/__init__.py +0 -0
  136. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/beacon_base.py +0 -0
  137. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/cat.py +0 -0
  138. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/drop_chara.py +0 -0
  139. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/gambling.py +0 -0
  140. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/gatya_item.py +0 -0
  141. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/item_pack.py +0 -0
  142. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/login_bonuses.py +0 -0
  143. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/matatabi.py +0 -0
  144. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/medals.py +0 -0
  145. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/mission.py +0 -0
  146. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/my_sale.py +0 -0
  147. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/nyanko_club.py +0 -0
  148. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/officer_pass.py +0 -0
  149. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/playtime.py +0 -0
  150. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/powerup.py +0 -0
  151. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/scheme_items.py +0 -0
  152. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/special_skill.py +0 -0
  153. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/stamp.py +0 -0
  154. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/talent_orbs.py +0 -0
  155. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/unlock_popups.py +0 -0
  156. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/upgrade.py +0 -0
  157. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/catbase/user_rank_rewards.py +0 -0
  158. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/__init__.py +0 -0
  159. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/base_materials.py +0 -0
  160. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/cat_shrine.py +0 -0
  161. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/catamins.py +0 -0
  162. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/gamatoto.py +0 -0
  163. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/gamoto/ototo.py +0 -0
  164. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/localizable.py +0 -0
  165. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/__init__.py +0 -0
  166. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/aku.py +0 -0
  167. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/challenge.py +0 -0
  168. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/chapters.py +0 -0
  169. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/dojo.py +0 -0
  170. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/enigma.py +0 -0
  171. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/event.py +0 -0
  172. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/ex_stage.py +0 -0
  173. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/gauntlets.py +0 -0
  174. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/item_reward_stage.py +0 -0
  175. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/legend_quest.py +0 -0
  176. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/map_names.py +0 -0
  177. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/map_option.py +0 -0
  178. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/map_reset.py +0 -0
  179. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/outbreaks.py +0 -0
  180. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/story.py +0 -0
  181. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/timed_score.py +0 -0
  182. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/tower.py +0 -0
  183. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/uncanny.py +0 -0
  184. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game/map/zero_legends.py +0 -0
  185. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/game_version.py +0 -0
  186. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/__init__.py +0 -0
  187. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/adb_handler.py +0 -0
  188. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/bc_csv.py +0 -0
  189. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/command.py +0 -0
  190. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/data.py +0 -0
  191. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/json_file.py +0 -0
  192. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/thread_helper.py +0 -0
  193. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/waydroid.py +0 -0
  194. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/io/yaml.py +0 -0
  195. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/max_value_helper.py +0 -0
  196. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/__init__.py +0 -0
  197. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/client_info.py +0 -0
  198. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/event_data.py +0 -0
  199. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/headers.py +0 -0
  200. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/managed_item.py +0 -0
  201. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/request.py +0 -0
  202. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/core/server/updater.py +0 -0
  203. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/config.properties +0 -0
  204. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/files.properties +0 -0
  205. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/input.properties +0 -0
  206. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/locale.properties +0 -0
  207. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/main.properties +0 -0
  208. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/server.properties +0 -0
  209. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/theme.properties +0 -0
  210. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/core/updater.properties +0 -0
  211. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/bannable_items.properties +0 -0
  212. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/enemy.properties +0 -0
  213. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/fixes.properties +0 -0
  214. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gambling.properties +0 -0
  215. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gamototo.properties +0 -0
  216. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gatya.properties +0 -0
  217. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/gold_pass.properties +0 -0
  218. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/items.properties +0 -0
  219. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/map.properties +0 -0
  220. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/medals.properties +0 -0
  221. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/missions.properties +0 -0
  222. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/playtime.properties +0 -0
  223. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/scheme_items.properties +0 -0
  224. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/talent_orbs.properties +0 -0
  225. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/treasures.properties +0 -0
  226. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/en/edits/user_rank.properties +0 -0
  227. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/locales/vi/metadata.json +0 -0
  228. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/max_values.json +0 -0
  229. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/themes/default.json +0 -0
  230. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/files/themes/discord.json +0 -0
  231. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe/py.typed +0 -0
  232. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe.egg-info/dependency_links.txt +0 -0
  233. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe.egg-info/entry_points.txt +0 -0
  234. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe.egg-info/requires.txt +0 -0
  235. {bcsfe-3.3.0 → bcsfe-3.4.0}/src/bcsfe.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bcsfe
3
- Version: 3.3.0
3
+ Version: 3.4.0
4
4
  Summary: A save file editor for The Battle Cats
5
5
  Author: fieryhenry
6
6
  License-Expression: GPL-3.0-or-later
@@ -56,6 +56,8 @@ test/develop new features
56
56
 
57
57
  - HungJoesifer for Vietnamese localization
58
58
 
59
+ - LinYuAn for Traditional Chinese localization
60
+
59
61
  ### Themes
60
62
 
61
63
  - HungJoesifer for the `discord` inspired theme
@@ -330,7 +332,7 @@ Once you have installed and ran the editor, you can now begin to edit your save
330
332
 
331
333
  1. In `The Battle Cats` enter the `Change Account / Device` menu in the `Settings` on the main menu.
332
334
 
333
- 2. Then enter the `Begin Data Transfer` menu.
335
+ 2. Then enter the `Change Device` -> `Retrieve Data from Old Device` menu.
334
336
 
335
337
  3. Then click / tap `Save Data to Server`, this should give you a transfer code and a confirmation
336
338
  code.
@@ -359,8 +361,8 @@ may also fail, if it does then try again.
359
361
  11. Back in-game, tap the `Close Game` button, then tap `Cancel Data Transfer` (and also possibly
360
362
  `Start Game From Beginning`)
361
363
 
362
- 12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer`
363
- menu
364
+ 12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer` ->
365
+ `Transfer Data to New Device` menu
364
366
 
365
367
  13. Enter the new codes, and tap `Resume Transfer`
366
368
 
@@ -27,6 +27,8 @@ test/develop new features
27
27
 
28
28
  - HungJoesifer for Vietnamese localization
29
29
 
30
+ - LinYuAn for Traditional Chinese localization
31
+
30
32
  ### Themes
31
33
 
32
34
  - HungJoesifer for the `discord` inspired theme
@@ -301,7 +303,7 @@ Once you have installed and ran the editor, you can now begin to edit your save
301
303
 
302
304
  1. In `The Battle Cats` enter the `Change Account / Device` menu in the `Settings` on the main menu.
303
305
 
304
- 2. Then enter the `Begin Data Transfer` menu.
306
+ 2. Then enter the `Change Device` -> `Retrieve Data from Old Device` menu.
305
307
 
306
308
  3. Then click / tap `Save Data to Server`, this should give you a transfer code and a confirmation
307
309
  code.
@@ -330,8 +332,8 @@ may also fail, if it does then try again.
330
332
  11. Back in-game, tap the `Close Game` button, then tap `Cancel Data Transfer` (and also possibly
331
333
  `Start Game From Beginning`)
332
334
 
333
- 12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer`
334
- menu
335
+ 12. Go back into the `Change Account / Device` menu and then go into the `Resume Data Transfer` ->
336
+ `Transfer Data to New Device` menu
335
337
 
336
338
  13. Enter the new codes, and tap `Resume Transfer`
337
339
 
@@ -1,4 +1,4 @@
1
- __version__ = "3.3.0"
1
+ __version__ = "3.4.0"
2
2
 
3
3
  from bcsfe import core, cli
4
4
 
@@ -18,19 +18,27 @@ def main():
18
18
  parser.add_argument(
19
19
  "--input-path", "-i", type=str, help="input path to save file to edit"
20
20
  )
21
+ parser.add_argument(
22
+ "--game-data-dir", "-g", type=str, help="path to store the game data to"
23
+ )
24
+ parser.add_argument(
25
+ "--transfer-backup-path",
26
+ type=str,
27
+ help="path to save the backup SAVE_DATA after transfering to",
28
+ )
21
29
  parser.add_argument(
22
30
  "--config-path",
23
31
  "-c",
24
32
  type=str,
25
33
  default=None,
26
- help="path to the config file. If unspecified defaults to Documents/bcsfe/config.yaml",
34
+ help=f"path to the config file. If unspecified defaults to {core.Config.get_config_path()}",
27
35
  )
28
36
  parser.add_argument(
29
37
  "--log-path",
30
38
  "-l",
31
39
  type=str,
32
40
  default=None,
33
- help="path to the log file. If unspecified defaults to Documents/bcsfe/bcsfe.log",
41
+ help=f"path to the log file. If unspecified defaults to {core.Logger.get_log_path()}",
34
42
  )
35
43
 
36
44
  args = parser.parse_args()
@@ -44,6 +52,12 @@ def main():
44
52
  if args.log_path is not None:
45
53
  core.set_log_path(core.Path(args.log_path))
46
54
 
55
+ if args.transfer_backup_path is not None:
56
+ core.set_transfer_backup_path(core.Path(args.transfer_backup_path))
57
+
58
+ if args.game_data_dir is not None:
59
+ core.set_game_data_path(core.Path(args.game_data_dir))
60
+
47
61
  core.core_data.init_data()
48
62
 
49
63
  try:
@@ -413,8 +413,9 @@ class CatEditor:
413
413
  if should_exit:
414
414
  return
415
415
  if upgrade is not None:
416
- power_up.reset_upgrade()
417
- power_up.upgrade_by(upgrade.base)
416
+ if upgrade.base != -1:
417
+ power_up.reset_upgrade()
418
+ power_up.upgrade_by(upgrade.base)
418
419
  cat.set_upgrade(self.save_file, upgrade, True)
419
420
  color.ColoredText.localize(
420
421
  "selected_cat_upgraded",
@@ -435,8 +436,9 @@ class CatEditor:
435
436
  success = True
436
437
  for cat in cats:
437
438
  power_up = core.PowerUpHelper(cat, self.save_file)
438
- power_up.reset_upgrade()
439
- power_up.upgrade_by(upgrade.base)
439
+ if upgrade.base != -1:
440
+ power_up.reset_upgrade()
441
+ power_up.upgrade_by(upgrade.base)
440
442
  cat.set_upgrade(self.save_file, upgrade, True)
441
443
  if success:
442
444
  color.ColoredText.localize("upgrade_success")
@@ -128,6 +128,23 @@ def edit_loop(save_file: core.SaveFile) -> bool:
128
128
  if editor is None:
129
129
  return False
130
130
 
131
+ new_cats: list[core.Cat] = []
132
+ for cat in cats:
133
+ names = cat.get_names_cls(save_file)
134
+ if names is None or not names:
135
+ name = core.localize("unknown")
136
+ else:
137
+ name = names[0]
138
+ quantity, _ = dialog_creator.IntInput(default=1).get_input_locale(
139
+ "cat_quantity", {"name": name, "id": cat.id}
140
+ )
141
+ if quantity is None:
142
+ return False
143
+ for _ in range(quantity):
144
+ new_cats.append(cat)
145
+
146
+ cats = new_cats
147
+
131
148
  space = get_storage_space(storage)
132
149
  if len(cats) > len(storage):
133
150
  color.ColoredText.localize(
@@ -164,6 +181,19 @@ def edit_loop(save_file: core.SaveFile) -> bool:
164
181
  if options is None:
165
182
  return False
166
183
 
184
+ items: list[core.StorageItem] = []
185
+
186
+ for id in options:
187
+ item = core.StorageItem.from_special_skill(id)
188
+
189
+ quantity, _ = dialog_creator.IntInput(default=1).get_input_locale(
190
+ "skill_quantity", {"name": skill_names[id]}
191
+ )
192
+ if quantity is None:
193
+ return False
194
+ for _ in range(quantity):
195
+ items.append(item)
196
+
167
197
  space = get_storage_space(storage)
168
198
  if len(options) > len(storage):
169
199
  color.ColoredText.localize(
@@ -177,8 +207,7 @@ def edit_loop(save_file: core.SaveFile) -> bool:
177
207
  return False
178
208
 
179
209
  color.ColoredText.localize("added_special_skills")
180
- for choice in options:
181
- item = core.StorageItem.from_special_skill(choice)
210
+ for item in items:
182
211
  add_item(storage, item)
183
212
  display_item(item, save_file)
184
213
 
@@ -8,7 +8,7 @@ class FeatureHandler:
8
8
  def __init__(self, save_file: core.SaveFile):
9
9
  self.save_file = save_file
10
10
 
11
- def get_features(self):
11
+ def get_features(self) -> dict[str, Any]:
12
12
  cat_features = {"cats": edits.cat_editor.CatEditor.edit_cats}
13
13
  if core.core_data.config.get_bool(core.ConfigKey.SEPARATE_CAT_EDIT_OPTIONS):
14
14
  cat_features = {
@@ -33,7 +33,9 @@ class FeatureHandler:
33
33
  "save_save": save_management.SaveManagement.save_save,
34
34
  "save_upload": save_management.SaveManagement.save_upload,
35
35
  "save_save_file": save_management.SaveManagement.save_save_dialog,
36
- "save_save_documents": save_management.SaveManagement.save_save_documents,
36
+ core.localize(
37
+ "save_save_documents", path=core.SaveFile.get_save_path()
38
+ ): save_management.SaveManagement.save_save_data_dir,
37
39
  "waydroid_push": save_management.SaveManagement.waydroid_push,
38
40
  "waydroid_push_rerun": save_management.SaveManagement.waydroid_push_rerun,
39
41
  "adb_push": save_management.SaveManagement.adb_push,
@@ -142,8 +144,7 @@ class FeatureHandler:
142
144
  }
143
145
  return features
144
146
 
145
- def get_feature(self, feature_name: str):
146
- feature_path = feature_name.split(".")
147
+ def get_feature(self, feature_path: list[str]):
147
148
  feature_dict = self.get_features()
148
149
  feature = feature_dict
149
150
  for path in feature_path:
@@ -154,10 +155,10 @@ class FeatureHandler:
154
155
  def search_features(
155
156
  self,
156
157
  name: str,
157
- parent_path: str = "",
158
+ current_path: list[str],
158
159
  features: dict[str, Any] | None = None,
159
- found_features: dict[str, int] | None = None,
160
- ) -> dict[str, int]:
160
+ found_features: dict[tuple[str, ...], int] | None = None,
161
+ ) -> dict[tuple[str, ...], int]:
161
162
  name = name.lower()
162
163
  if features is None:
163
164
  features = self.get_features()
@@ -166,9 +167,8 @@ class FeatureHandler:
166
167
 
167
168
  for feature_name_key, feature in features.items():
168
169
  feature_name = core.core_data.local_manager.get_key(feature_name_key)
169
- path = (
170
- f"{parent_path}.{feature_name_key}" if parent_path else feature_name_key
171
- )
170
+ path = current_path.copy()
171
+ path.append(feature_name_key)
172
172
  if isinstance(feature, dict):
173
173
  found_features.update(
174
174
  self.search_features(
@@ -180,34 +180,36 @@ class FeatureHandler:
180
180
  )
181
181
  for alias in core.LocalManager.get_all_aliases(feature_name):
182
182
  if not name:
183
- found_features[path] = 100
183
+ found_features[*path] = 100
184
184
  break
185
185
  alias = alias.lower()
186
186
 
187
187
  name = name.replace(" ", "")
188
188
  alias = alias.replace(" ", "")
189
189
  if alias in name or name in alias:
190
- found_features[path] = 100
190
+ found_features[*path] = 100
191
191
  break
192
192
 
193
193
  return found_features
194
194
 
195
- def display_features(self, features: list[str]):
195
+ def display_features(self, features: list[list[str]]):
196
196
  feature_names: list[str] = []
197
197
  for feature_name in features:
198
- feature_names.append(feature_name.split(".")[-1])
198
+ feature_names.append(feature_name[-1])
199
199
  print()
200
200
  dialog_creator.ListOutput(feature_names, [], "features", {}).display_locale(
201
201
  remove_alias=True
202
202
  )
203
203
 
204
- def select_features(self, features: list[str], parent_path: str = "") -> list[str]:
204
+ def select_features(
205
+ self, features: list[list[str]], current_path: list[str]
206
+ ) -> list[list[str]]:
205
207
  if features != list(self.get_features().keys()):
206
- features.insert(0, "go_back")
208
+ features.insert(0, ["go_back"])
207
209
  self.display_features(features)
208
210
  print()
209
211
  usr_input = color.ColoredInput().localize("select_features").strip()
210
- selected_features: list[str] = []
212
+ selected_features: list[list[str]] = []
211
213
  if usr_input.isdigit():
212
214
  usr_input = int(usr_input)
213
215
  if usr_input > len(features):
@@ -216,59 +218,53 @@ class FeatureHandler:
216
218
  color.ColoredText.localize("invalid_input")
217
219
  else:
218
220
  feature_name_top = features[usr_input - 1]
219
- if feature_name_top == "go_back":
220
- return list(self.get_features().keys())
221
+ if feature_name_top == ["go_back"]:
222
+ return [[k] for k in self.get_features().keys()]
221
223
  feature = self.get_feature(feature_name_top)
222
224
  if isinstance(feature, dict):
223
225
  for feature_name in feature.keys(): # type: ignore
224
- feature_path = (
225
- f"{parent_path}.{feature_name_top}.{feature_name}"
226
- if parent_path
227
- else f"{feature_name_top}.{feature_name}"
228
- )
226
+ feature_path: list[str] = current_path.copy()
227
+ feature_path.extend(feature_name_top + [feature_name])
229
228
  selected_features.append(feature_path)
230
229
 
231
230
  else:
232
- feature_path = (
233
- f"{parent_path}.{feature_name_top}"
234
- if parent_path
235
- else feature_name_top
236
- )
231
+ feature_path = current_path.copy()
232
+ feature_path.extend(feature_name_top)
237
233
  selected_features.append(feature_path)
238
234
 
239
235
  else:
240
- feats = self.search_features(usr_input)
236
+ feats = self.search_features(usr_input, [])
241
237
  if not feats:
242
238
  color.ColoredText.localize("no_feature_with_name", name=usr_input)
243
239
  kv_map = list(feats.items())
244
240
  kv_map.sort(key=lambda v: v[1], reverse=True)
245
- selected_features = [v[0] for v in kv_map]
241
+ selected_features = [list(v[0]) for v in kv_map]
246
242
 
247
243
  return selected_features
248
244
 
249
245
  def select_features_run(self):
250
- features = self.get_features()
251
- features = list(features.keys())
246
+ features_dict = self.get_features()
247
+ features: list[list[str]] = [[k] for k in features_dict.keys()]
252
248
  self.save_file.to_file_thread(self.save_file.get_temp_path())
253
249
  edits.clear_tutorial.clear_tutorial(self.save_file, False)
254
250
  self.save_file.show_ban_message = False
255
251
 
256
252
  while True:
257
- features = self.select_features(features)
253
+ features = self.select_features(features, [])
258
254
 
259
- new_features: list[str] = []
255
+ new_features: list[list[str]] = []
260
256
  found_strs: list[str] = []
261
257
  for feature_ in features:
262
- if feature_.split(".")[-1] in found_strs:
258
+ if feature_[-1] in found_strs:
263
259
  continue
264
- found_strs.append(feature_.split(".")[-1])
260
+ found_strs.append(feature_[-1])
265
261
  new_features.append(feature_)
266
262
 
267
263
  features = new_features
268
264
  feature = None
269
265
  if len(features) == 1:
270
266
  feature = features[0]
271
- if len(features) == 2 and features[0] == "go_back":
267
+ if len(features) == 2 and features[0] == ["go_back"]:
272
268
  feature = features[1]
273
269
 
274
270
  if not feature:
@@ -283,8 +279,8 @@ class FeatureHandler:
283
279
 
284
280
  self.save_file.to_file_thread(self.save_file.get_temp_path())
285
281
 
286
- features = self.get_features()
287
- features = list(features.keys())
282
+ features_dict = self.get_features()
283
+ features = [[k] for k in features_dict.keys()]
288
284
 
289
285
  core.core_data.game_data_getter = None # reset game data getter so that if an old version is removed, it will download the new version
290
286
 
@@ -291,10 +291,8 @@ class Main:
291
291
  return None
292
292
  try:
293
293
  json_data = core.JsonFile.from_data(path.read()).to_object()
294
- except core.JSONDecodeError:
295
- color.ColoredText.localize(
296
- "load_json_fail", error=core.core_data.logger.get_traceback()
297
- )
294
+ except (core.JSONDecodeError, UnicodeDecodeError):
295
+ color.ColoredText.localize("parse_json_fail")
298
296
  return None
299
297
  try:
300
298
  save_file = core.SaveFile.from_dict(json_data)
@@ -89,7 +89,10 @@ class RecentSaves:
89
89
  def to_path(self, path: core.Path):
90
90
  data = json.dumps(self.to_json(), indent=4)
91
91
 
92
- path.write(core.Data(data))
92
+ try:
93
+ path.write(core.Data(data))
94
+ except Exception as e:
95
+ print(e)
93
96
 
94
97
  @staticmethod
95
98
  def read_default() -> RecentSaves:
@@ -100,7 +103,7 @@ class RecentSaves:
100
103
 
101
104
  @staticmethod
102
105
  def get_path() -> core.Path:
103
- return core.Path.get_documents_folder().add("recent_saves.json")
106
+ return core.Path.get_data_folder().add("recent_saves.json")
104
107
 
105
108
  def save_default(self):
106
109
  path = RecentSaves.get_path()
@@ -27,7 +27,11 @@ class SaveManagement:
27
27
  if save_file.save_path is None:
28
28
  return
29
29
 
30
- save_file.to_file(save_file.save_path)
30
+ try:
31
+ save_file.to_file(save_file.save_path)
32
+ except OSError as e:
33
+ print(e)
34
+ return
31
35
 
32
36
  color.ColoredText.localize("save_success", path=save_file.save_path)
33
37
 
@@ -48,14 +52,14 @@ class SaveManagement:
48
52
  color.ColoredText.localize("save_success", path=save_file.save_path)
49
53
 
50
54
  @staticmethod
51
- def save_save_documents(save_file: core.SaveFile):
52
- """Save the save file to the documents folder.
55
+ def save_save_data_dir(save_file: core.SaveFile):
56
+ """Save the save file to the data folder.
53
57
 
54
58
  Args:
55
59
  save_file (core.SaveFile): The save file to save.
56
60
  """
57
61
  SaveManagement.upload_items_checker(save_file)
58
- save_file.save_path = core.SaveFile.get_saves_path().add("SAVE_DATA")
62
+ save_file.save_path = core.SaveFile.get_save_path()
59
63
  save_file.to_file(save_file.save_path)
60
64
  color.ColoredText.localize("save_success", path=save_file.save_path)
61
65
 
@@ -356,11 +360,9 @@ class SaveManagement:
356
360
  options = [
357
361
  "download_save",
358
362
  "select_save_file",
359
- "load_from_documents",
363
+ core.localize("load_from_documents", path=core.SaveFile.get_save_path()),
360
364
  "adb_pull_save",
361
365
  "load_save_data_json",
362
- # "load_recent_saves",
363
- # "create_new_save",
364
366
  ]
365
367
  if starting_options:
366
368
  options.append("edit_config")
@@ -577,7 +579,10 @@ class SaveManagement:
577
579
 
578
580
  save_file.save_path = save_path
579
581
  backup_path = save_file.get_default_path()
580
- save_file.save_path.copy_thread(backup_path)
582
+ try:
583
+ save_file.save_path.copy_thread(backup_path)
584
+ except Exception as e:
585
+ print(e)
581
586
  save_file.used_storage = used_storage
582
587
 
583
588
  return save_file, backup_path
@@ -64,7 +64,13 @@ class ServerCLI:
64
64
  if path is None:
65
65
  return None
66
66
 
67
- save_file.to_file(path)
67
+ try:
68
+ save_file.to_file(path)
69
+ except OSError as e:
70
+ print(
71
+ f"failed to write save file to: {path} due to: {e}. Skipping writing the save file to disk"
72
+ )
73
+ input("press enter to continue anyway")
68
74
 
69
75
  color.ColoredText.localize("save_downloaded", path=path.to_str())
70
76
 
@@ -299,6 +299,8 @@ class CoreData:
299
299
  config_path = None
300
300
  print_config_err = True
301
301
  log_path = None
302
+ transfer_backup_path = None
303
+ game_data_path = None
302
304
 
303
305
 
304
306
  def set_config_path(path: Path):
@@ -306,11 +308,29 @@ def set_config_path(path: Path):
306
308
  config_path = path
307
309
 
308
310
 
311
+ def set_game_data_path(path: Path):
312
+ global game_data_path
313
+ game_data_path = path
314
+
315
+
309
316
  def set_log_path(path: Path):
310
317
  global log_path
311
318
  log_path = path
312
319
 
313
320
 
321
+ def set_transfer_backup_path(path: Path):
322
+ global transfer_backup_path
323
+ transfer_backup_path = path
324
+
325
+
326
+ def get_transfer_backup_path() -> Path | None:
327
+ return transfer_backup_path
328
+
329
+
330
+ def get_game_data_path() -> Path | None:
331
+ return game_data_path
332
+
333
+
314
334
  def update_external_content(_: Any = None):
315
335
  """Updates external content."""
316
336
 
@@ -235,7 +235,7 @@ class GatyaInfo:
235
235
 
236
236
  def get_file_path(self) -> core.Path:
237
237
  return (
238
- core.Path.get_documents_folder()
238
+ core.Path.get_data_folder()
239
239
  .add("other_game_data")
240
240
  .add(self.cc.get_code())
241
241
  .add("gatya_info")
@@ -48,7 +48,7 @@ class Config:
48
48
 
49
49
  @staticmethod
50
50
  def get_config_path() -> core.Path:
51
- return core.Path.get_documents_folder().add("config.yaml")
51
+ return core.Path.get_config_folder().add("config.yaml")
52
52
 
53
53
  def __getitem__(self, key: ConfigKey) -> Any:
54
54
  return self.config[key]
@@ -52,9 +52,7 @@ class Repo:
52
52
  except FileNotFoundError:
53
53
  return None
54
54
 
55
- def get_temp_file(
56
- self, temp_folder: core.Path, file_path: core.Path
57
- ) -> core.Data:
55
+ def get_temp_file(self, temp_folder: core.Path, file_path: core.Path) -> core.Data:
58
56
  path = temp_folder.add(file_path)
59
57
  return path.read()
60
58
 
@@ -74,7 +72,7 @@ class Repo:
74
72
  class GitHandler:
75
73
  @staticmethod
76
74
  def get_repo_folder() -> core.Path:
77
- repo_folder = core.Path.get_documents_folder().add("repos")
75
+ repo_folder = core.Path.get_data_folder().add("repos")
78
76
  repo_folder.generate_dirs()
79
77
  return repo_folder
80
78
 
@@ -74,12 +74,22 @@ class Path:
74
74
  return self.path.replace("\\", "/")
75
75
 
76
76
  @staticmethod
77
- def get_documents_folder(app_name: str = "bcsfe") -> Path:
77
+ def get_data_folder(app_name: str = "bcsfe") -> Path:
78
78
  os_name = os.name
79
79
  if os_name == "nt":
80
80
  path = Path.join(os.environ["USERPROFILE"], "Documents", app_name)
81
81
  elif os_name == "posix":
82
- path = Path.join(os.environ["HOME"], "Documents", app_name)
82
+ data_home = os.environ.get("XDG_DATA_HOME")
83
+ if data_home is None:
84
+ path = Path.join(os.environ["HOME"], ".local", "share", app_name)
85
+ else:
86
+ path = Path.join(data_home, app_name)
87
+
88
+ # migrate old data
89
+ if path.is_empty():
90
+ orig = Path.join(os.environ["HOME"], "Documents", app_name)
91
+ orig.copy(path)
92
+
83
93
  elif os_name == "mac":
84
94
  path = Path.join(os.environ["HOME"], "Documents", app_name)
85
95
  else:
@@ -87,6 +97,41 @@ class Path:
87
97
  path.generate_dirs()
88
98
  return path
89
99
 
100
+ @staticmethod
101
+ def get_config_folder(app_name: str = "bcsfe") -> Path:
102
+ os_name = os.name
103
+ if os_name != "posix":
104
+ return Path.get_data_folder()
105
+
106
+ data_home = os.environ.get("XDG_CONFIG_HOME")
107
+ if data_home is None:
108
+ path = Path.join(os.environ["HOME"], ".config", app_name)
109
+ else:
110
+ path = Path.join(data_home, app_name)
111
+ path.generate_dirs()
112
+
113
+ # migrate from old Documents location
114
+ if path.is_empty():
115
+ orig = Path.join(os.environ["HOME"], "Documents", app_name, "config.yaml")
116
+ if orig.exists():
117
+ orig.copy(path.join("config.yaml"))
118
+ return path
119
+
120
+ @staticmethod
121
+ def get_state_folder(app_name: str = "bcsfe") -> Path:
122
+ os_name = os.name
123
+ if os_name != "posix":
124
+ return Path.get_data_folder()
125
+ data_home = os.environ.get("XDG_STATE_HOME")
126
+ if data_home is None:
127
+ path = Path.join(os.environ["HOME"], ".local", "state", app_name)
128
+ else:
129
+ path = Path.join(data_home, app_name)
130
+ path.generate_dirs()
131
+
132
+ # no need to migrate log file really
133
+ return path
134
+
90
135
  def is_empty(self) -> bool:
91
136
  return self.path == ""
92
137
 
@@ -100,11 +145,6 @@ class Path:
100
145
  print(e, self)
101
146
  return self
102
147
 
103
- def create(self) -> Path:
104
- if not self.exists():
105
- self.write(core.Data("test"))
106
- return self
107
-
108
148
  def exists(self) -> bool:
109
149
  return os.path.exists(self.path)
110
150
 
@@ -78,7 +78,7 @@ class RootHandler:
78
78
  self, local_path: core.Path | None = None
79
79
  ) -> tuple[core.Path | None, core.CommandResult]:
80
80
  if local_path is None:
81
- local_path = core.Path.get_documents_folder().add("saves").add("SAVE_DATA")
81
+ local_path = core.Path.get_data_folder().add("saves").add("SAVE_DATA")
82
82
  local_path.parent().generate_dirs()
83
83
  result = self.save_battlecats_save(local_path)
84
84
  if not result.success: