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.
|
|
Binary 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"
|