ac6-manager 0.1.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.
@@ -0,0 +1,51 @@
1
+ ac6-manager Non-Commercial Source License
2
+
3
+ Copyright © 2026 Danila Kolesnikov
4
+
5
+ 1. Grant of Permission
6
+ Permission is granted, free of charge, to any person obtaining a copy of
7
+ this software and its source code (the "Software") to use, copy, modify,
8
+ and redistribute it, originally or modified, for any purpose, subject to
9
+ the restrictions below.
10
+
11
+ 2. Restriction on Sale
12
+ The Software, whether in its original or modified form, may not be sold,
13
+ licensed for a fee, or otherwise distributed in exchange for payment.
14
+
15
+ This restriction applies only to the Software itself and does not restrict
16
+ the sale of other works that use, depend upon, or are produced using the
17
+ Software, provided that the Software itself is not being sold or distributed
18
+ in exchange for payment.
19
+
20
+ 3. Attribution
21
+ Attribution to the original author is appreciated, but not required.
22
+
23
+ You may modify, rename, and redistribute the Software without identifying
24
+ yourself as the original author, provided altered versions are plainly
25
+ marked and you do not falsely claim to have created the original Software.
26
+
27
+ 4. Third-Party Material
28
+ This license applies only to the Software and other material the copyright
29
+ holder has the right to license.
30
+
31
+ In particular, this license does not apply to third-party assets, game data,
32
+ configuration files, or user data bundled with or referenced by the Software,
33
+ including 'blank_save.sl2'. That particular file is a save file
34
+ generated by Armored Core VI; it is not claimed as an original work of the
35
+ author, and no rights to it are granted.
36
+
37
+ Armored Core VI and its associated intellectual property belong to their
38
+ respective rights holders.
39
+
40
+ 5. Disclaimer
41
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING
45
+ FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
46
+ IN THE SOFTWARE.
47
+
48
+ 6. Termination
49
+ Any permission granted under this license terminates automatically upon a
50
+ material violation of its terms. Permissions granted to you before such a
51
+ violation remain unaffected.
@@ -0,0 +1,38 @@
1
+ Metadata-Version: 2.5
2
+ Name: ac6-manager
3
+ Version: 0.1.0
4
+ Summary: An Armored Core 6 save manager
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
9
+ # ac6-manager
10
+ A CLI save manager for **Armored Core VI**.
11
+
12
+ AC6 can only have one save file at a time. While this is normally not an issue, it gets really annoying when you, for example, have already finished New Game++ and want a fresh experience without losing hours of progress. `ac6-manager` solves this by allowing you to create and manage new saves in a local folder without having to manually go into the save folder and risk breaking the game.
13
+
14
+ **As of now,** `ac6-manager` **only works with Steam Proton on Linux**. While other systems may be supported in the future, it is not guaranteed.
15
+
16
+ ## Install
17
+ ```
18
+ pipx install ac6-manager
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ ac6-manager [operation] 'target file'
25
+ ```
26
+ | Command | Description |
27
+ |---|---|
28
+ | `ac6-manager config` | Changes current configuration |
29
+ | `ac6-manager status` | Lists tool version, config, and current saves |
30
+ | `ac6-manager create 'new_save_name'` | Creates a new save file with the given name |
31
+ | `ac6-manager rename 'old_save_name' 'new_save_name'` | Renames the given save file |
32
+ | `ac6-manager switch 'inactive_save'` | Switches the current active save with the given one |
33
+ | `ac6-manager delete 'inactive_save'` | Deletes the given save file if it's inactive |
34
+
35
+ On first run (or via `ac6-manager config`), you will be asked for your Steam library path and SteamID64 so the tool can find your current AC6 save. From there, the save will automatically be registered by the tool without further setup. Do **NOT** switch saves with the game running, as doing so will corrupt both saves involved.
36
+
37
+ ## License
38
+ Licensed under the ac6-manager Non-Commercial Source License. This software is free to use, copy, modify, and redistribute. It may not be distributed for direct payment. Full license included in the package under `dist-info/licenses/LICENSE`.
@@ -0,0 +1,30 @@
1
+ # ac6-manager
2
+ A CLI save manager for **Armored Core VI**.
3
+
4
+ AC6 can only have one save file at a time. While this is normally not an issue, it gets really annoying when you, for example, have already finished New Game++ and want a fresh experience without losing hours of progress. `ac6-manager` solves this by allowing you to create and manage new saves in a local folder without having to manually go into the save folder and risk breaking the game.
5
+
6
+ **As of now,** `ac6-manager` **only works with Steam Proton on Linux**. While other systems may be supported in the future, it is not guaranteed.
7
+
8
+ ## Install
9
+ ```
10
+ pipx install ac6-manager
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```
16
+ ac6-manager [operation] 'target file'
17
+ ```
18
+ | Command | Description |
19
+ |---|---|
20
+ | `ac6-manager config` | Changes current configuration |
21
+ | `ac6-manager status` | Lists tool version, config, and current saves |
22
+ | `ac6-manager create 'new_save_name'` | Creates a new save file with the given name |
23
+ | `ac6-manager rename 'old_save_name' 'new_save_name'` | Renames the given save file |
24
+ | `ac6-manager switch 'inactive_save'` | Switches the current active save with the given one |
25
+ | `ac6-manager delete 'inactive_save'` | Deletes the given save file if it's inactive |
26
+
27
+ On first run (or via `ac6-manager config`), you will be asked for your Steam library path and SteamID64 so the tool can find your current AC6 save. From there, the save will automatically be registered by the tool without further setup. Do **NOT** switch saves with the game running, as doing so will corrupt both saves involved.
28
+
29
+ ## License
30
+ Licensed under the ac6-manager Non-Commercial Source License. This software is free to use, copy, modify, and redistribute. It may not be distributed for direct payment. Full license included in the package under `dist-info/licenses/LICENSE`.
@@ -0,0 +1 @@
1
+ # SERIOUSLY fuck pip for requiring I have this file.
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env python3
2
+ import sys
3
+ import os
4
+ import shutil
5
+ import json
6
+ from importlib.metadata import version
7
+
8
+
9
+ # setup
10
+ user_data_dir = f"{os.path.expanduser('~')}/.local/share/ac6-manager"
11
+ os.makedirs(f"{user_data_dir}/user_saves/", exist_ok=True)
12
+
13
+ def error(message):
14
+ print("ac6-manager:", message)
15
+ sys.exit(1)
16
+
17
+ def load_config():
18
+ try:
19
+ with open(f"{user_data_dir}/config.json", "r") as config_file:
20
+ return json.load(config_file)
21
+ except FileNotFoundError:
22
+ print("Config not found. Manual setup required.")
23
+ reset_config()
24
+ return load_config() # retry loading
25
+
26
+
27
+ # command functions
28
+ def reset_config():
29
+ if os.path.exists(f"{user_data_dir}/config.json"):
30
+ old_config = load_config()
31
+ else:
32
+ os.mkdir(f"{user_data_dir}/user_saves/First Save/")
33
+ old_config = {
34
+ "steam_lib_path": "",
35
+ "steam_id": "",
36
+ "active_save": "First Save"
37
+ }
38
+
39
+ def input_path():
40
+ while True:
41
+ path= input(
42
+ "Input your full Steam library path. It can be "
43
+ "found in Steam(top left)>Settings>Storage\n"
44
+ f"Your previous path was: {old_config['steam_lib_path']}\n"
45
+ "> "
46
+ ).strip()
47
+ if os.path.exists(path):
48
+ return path.rstrip("/") + "/"
49
+ print("Nonexistant path. Please try again.")
50
+
51
+ def input_id():
52
+ while True:
53
+ user_id = input(
54
+ "Input your SteamID64. It can be found in Steam "
55
+ "'Account details'; your ID is under your account name\n"
56
+ f"Your previous SteamID64 was: {old_config['steam_id']}\n"
57
+ "> "
58
+ ).strip()
59
+ if user_id.isdigit() and len(user_id)==17 and int(user_id)>76561197960265728:
60
+ return user_id
61
+ print("Invalid SteamID64. Please try again.")
62
+
63
+ with open(f"{user_data_dir}/config.json", "w") as config_file:
64
+ json.dump(
65
+ {
66
+ "steam_lib_path": input_path(),
67
+ "steam_id": input_id(),
68
+ "active_save": old_config["active_save"]
69
+ },
70
+ config_file
71
+ )
72
+
73
+ def status():
74
+ saves = [f.name for f in os.scandir(f"{user_data_dir}/user_saves/") if f.is_dir()]
75
+ configs = load_config()
76
+
77
+ print(
78
+ f"Version: {version('ac6-manager')}\n"
79
+ f"Steam library: {configs['steam_lib_path']}\n"
80
+ f"SteamID64: {configs['steam_id']}\n"
81
+ "Saves:"
82
+ )
83
+ for save in saves:
84
+ print(f" {save+' (Active)'*(save==configs['active_save'])}")
85
+
86
+ def create(save_name):
87
+ if (save_name in (".", "..")) or ("/" in save_name) or ("\0" in save_name):
88
+ error("create: Invalid file name")
89
+ try:
90
+ os.mkdir(f"{user_data_dir}/user_saves/{save_name}/")
91
+ except FileExistsError:
92
+ error(f"create: '{save_name}' already taken")
93
+ shutil.copy2(
94
+ f"{os.path.dirname(os.path.abspath(__file__))}/blank_save.sl2",
95
+ f"{user_data_dir}/user_saves/{save_name}/AC60000.sl2"
96
+ )
97
+
98
+ def rename(save_1, save_2):
99
+ if not os.path.exists(f"{user_data_dir}/user_saves/{save_1}/"):
100
+ error("rename: Save not found")
101
+ elif (save_2 in (".", "..")) or ("/" in save_2) or ("\0" in save_2):
102
+ error("rename: Invalid file name")
103
+ elif save_1 == save_2:
104
+ print("rename: Save name unchanged")
105
+ return
106
+ elif os.path.exists(f"{user_data_dir}/user_saves/{save_2}/"):
107
+ error(f"rename: '{save_2}' already taken")
108
+
109
+ configs = load_config()
110
+ if configs["active_save"] == save_1:
111
+ configs["active_save"] = save_2
112
+ with open(f"{user_data_dir}/config.json", "w") as config_file:
113
+ json.dump(configs, config_file)
114
+
115
+ os.rename(
116
+ f"{user_data_dir}/user_saves/{save_1}/",
117
+ f"{user_data_dir}/user_saves/{save_2}/"
118
+ )
119
+
120
+ def switch(save_name):
121
+ configs = load_config()
122
+ if not os.path.isdir(f"{user_data_dir}/user_saves/{save_name}/"):
123
+ error("switch: Save not found")
124
+ elif save_name == configs["active_save"]:
125
+ print("switch: Save already active")
126
+ return
127
+
128
+ # save movement
129
+ save_dir = (
130
+ configs["steam_lib_path"] +
131
+ "steamapps/compatdata/1888160/pfx/drive_c/users/steamuser/AppData/Roaming/ArmoredCore6/" +
132
+ configs["steam_id"]
133
+ )
134
+ try:
135
+ shutil.move(
136
+ f"{save_dir}/AC60000.sl2",
137
+ f"{user_data_dir}/user_saves/{configs['active_save']}/AC60000.sl2"
138
+ )
139
+ shutil.move(
140
+ f"{user_data_dir}/user_saves/{save_name}/AC60000.sl2",
141
+ f"{save_dir}/AC60000.sl2"
142
+ )
143
+ except Exception as e:
144
+ error(f"switch: File movement interrupted ({e}): manual recovery may be required")
145
+
146
+ # active save change
147
+ configs["active_save"] = save_name
148
+ with open(f"{user_data_dir}/config.json", "w") as config_file:
149
+ json.dump(configs, config_file)
150
+
151
+ def delete(save_name):
152
+ if not os.path.exists(f"{user_data_dir}/user_saves/{save_name}/"):
153
+ error("delete: Save not found")
154
+ elif save_name == load_config()["active_save"]:
155
+ error("delete: Save currently active")
156
+ elif input("Type 'DELETE' to confirm: ") == "DELETE":
157
+ shutil.rmtree(f"{user_data_dir}/user_saves/{save_name}/")
158
+ else:
159
+ print("Deletion aborted")
160
+
161
+
162
+ # main function
163
+ def main():
164
+ match sys.argv:
165
+ case [_]:
166
+ print(
167
+ "Usage: ac6-manager [operation] 'target file'\n"
168
+ "Operations:\n"
169
+ " ac6-manager config "
170
+ "Changes current configuration\n"
171
+ " ac6-manager status "
172
+ "Lists tool version, config, and current saves\n"
173
+ " ac6-manager create 'new_save_name' "
174
+ "Creates a new save file with the given name\n"
175
+ " ac6-manager rename 'old_save_name' 'new_save_name' "
176
+ "Renames the given save file\n"
177
+ " ac6-manager switch 'inactive file' "
178
+ "Switches the current active save with the given one\n"
179
+ " ac6-manager delete 'inactive file' "
180
+ "Deletes the given save file if it's inactive"
181
+ )
182
+ case [_, "config"]:
183
+ reset_config()
184
+ case [_, "config", *args]:
185
+ error(f"config: Unknown arguments: {args}")
186
+
187
+ case [_, "status"]:
188
+ status()
189
+ case [_, "status", *args]:
190
+ error(f"status: Unknown arguments: {args}")
191
+
192
+ case [_, "create"]:
193
+ error("create: Missing argument")
194
+ case [_, "create", save_name]:
195
+ create(save_name)
196
+ case [_, "create", _, *args]:
197
+ error(f"create: Unknown arguments: {args}")
198
+
199
+ case [_, "rename"]:
200
+ error("rename: Missing arguments")
201
+ case [_, "rename", _]:
202
+ error("rename: Missing argument")
203
+ case [_, "rename", old_name, new_name]:
204
+ rename(old_name, new_name)
205
+ case [_, "rename", _, _, *args]:
206
+ error(f"rename: Unknown arguments: {args}")
207
+
208
+ case [_, "switch"]:
209
+ error("switch: Missing argument")
210
+ case [_, "switch", target_save]:
211
+ switch(target_save)
212
+ case [_, "switch", _, *args]:
213
+ error(f"switch: Unknown arguments: {args}")
214
+
215
+ case [_, "delete"]:
216
+ error("delete: Missing argument")
217
+ case [_, "delete", target_save]:
218
+ delete(target_save)
219
+ case [_, "delete", _, *args]:
220
+ error(f"delete: Unknown arguments: {args}")
221
+
222
+ case _:
223
+ error("Unknown operation")
224
+
225
+
226
+ # testing enabler
227
+ if __name__ == "__main__":
228
+ main()
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ac6-manager"
7
+ version = "0.1.0"
8
+ description = "An Armored Core 6 save manager"
9
+ readme = "README.md"
10
+ dependencies = []
11
+ requires-python = ">=3.10"
12
+ license-files = ["LICENSE"]
13
+
14
+ [project.scripts]
15
+ ac6-manager = "ac6_manager.main:main"
16
+
17
+ [tool.hatch.build.targets.wheel]
18
+ packages = ["ac6_manager"]
19
+
20
+ [tool.hatch.build.targets.wheel.force-include]
21
+ "ac6_manager/blank_save.sl2" = "ac6_manager/blank_save.sl2"