init
commit
98d34ebbac
|
@ -0,0 +1,4 @@
|
||||||
|
*.bck
|
||||||
|
*.bak
|
||||||
|
*\~
|
||||||
|
*.swp
|
|
@ -0,0 +1,34 @@
|
||||||
|
# R2mods
|
||||||
|
|
||||||
|
Knowledge dumping on ror2 modding community - how I can improve everything, as well as
|
||||||
|
keeping all of the code (or disassembled) dump in one place - tracking with a modpack
|
||||||
|
that me and my frenns are playing, duped `choncc`
|
||||||
|
|
||||||
|
## Merging codebase across multiple sources
|
||||||
|
|
||||||
|
This is the ultimate test for Git knowledge, you can't just go and submodule everything.
|
||||||
|
I'll maintain this along with `choncc` and dump as many versions of the mods being tracked
|
||||||
|
|
||||||
|
## Disassemblies
|
||||||
|
|
||||||
|
Use this IN CONJUNCTION WITH original code if available. This is mostly because code quality
|
||||||
|
from conventional codebase is no simpler than the disassembled code (surprisingly?).
|
||||||
|
|
||||||
|
Will go onto [ilspy_dump](./ilspy_dump), before we figure out how to use `ilspycmd`, we'll
|
||||||
|
just use the GUI.
|
||||||
|
|
||||||
|
For now, no naming convention yet, I'll try to export both a singular C# file AND the whole C# project
|
||||||
|
|
||||||
|
- `ror2.dll` is in `//SteamLibrary/steamapps/common/Risk\ of\ Rain\ 2/Risk\ of\ Rain\ 2_Data/Managed/ror2.dll`
|
||||||
|
|
||||||
|
## R2 profile footprint
|
||||||
|
|
||||||
|
Per the code (TODO: ADD SOURCEGRAPH QUERY AND CODE HERE), it only contain mod manifests and configurations,
|
||||||
|
very little non-configuration files are in here because file extensions are hard-coded for filter during
|
||||||
|
profile sharing process.
|
||||||
|
|
||||||
|
**Locations of mod profiles**
|
||||||
|
|
||||||
|
- [r2modman](https://github.com/ebkr/r2modmanPlus/tags) is in `%AppData%/r2modmanPlus-local/RiskOfRain2/profiles`
|
||||||
|
- [thunderstore (WARNING: DOWNLOAD ON CLICK)](https://www.overwolf.com/app/Thunderstore-Thunderstore_Mod_Manager) is in `%AppData%/Thunderstore\ Mod\ Manager/DataFolder/RiskOfRain2/profiles`
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import os.path
|
||||||
|
import pathlib
|
||||||
|
import zipfile
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
|
||||||
|
logging.config.dictConfig({
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': False,
|
||||||
|
'formatters': {
|
||||||
|
'standard': {
|
||||||
|
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'console': {
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'formatter': 'standard',
|
||||||
|
'stream': 'ext://sys.stderr',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
'': { # root logger
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'propagate': True
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
def extract(zip_path: str, dest: str, skip_checks: bool = False):
|
||||||
|
"""
|
||||||
|
Did you know that `.r2z` is just a badly compressed zip?
|
||||||
|
|
||||||
|
Utilized to automate version controlling configs and plugin manifests
|
||||||
|
|
||||||
|
NB: Do not use this to install profiles. Most mod manager has an install step
|
||||||
|
after extracting.
|
||||||
|
|
||||||
|
`dest` needs to be profiled path, that is, should be something like
|
||||||
|
`//profiles/my-profile`, not just `//profiles` with `zip_path`
|
||||||
|
`//exports/my-profile`
|
||||||
|
"""
|
||||||
|
p = pathlib.Path(zip_path)
|
||||||
|
to_dir = pathlib.Path(dest)
|
||||||
|
if to_dir.is_file():
|
||||||
|
raise KeyError("Expected dest to be directory or be recursively made")
|
||||||
|
|
||||||
|
if not p.suffix.lower() == ".r2z" and not skip_checks:
|
||||||
|
raise KeyError("Expected r2z suffix, use `skip_checks` to bypass")
|
||||||
|
|
||||||
|
profile_dir = to_dir
|
||||||
|
os.makedirs(profile_dir, exist_ok=True)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(p, 'r') as zip_ref:
|
||||||
|
logging.info(f"Extracting {p} to {profile_dir}")
|
||||||
|
zip_ref.extractall(profile_dir)
|
||||||
|
|
||||||
|
def repo_root_impure():
|
||||||
|
cwd = pathlib.Path.cwd()
|
||||||
|
return cwd.parent if cwd.name == "script" else cwd
|
||||||
|
|
||||||
|
def main():
|
||||||
|
dry_run = os.getenv("DRY_RUN", "").lower() not in ("false", "0", "no", "nope")
|
||||||
|
if dry_run: logger.debug("Doing dry run")
|
||||||
|
|
||||||
|
ror2_f = "RiskOfRain2"
|
||||||
|
MODMAN_PATH_ENV = "ROR2_MODMAN_PATH"
|
||||||
|
MODMAN_CANDIDATES = [
|
||||||
|
pathlib.Path.home().joinpath("AppData","Roaming", *modman_segs, ror2_f)
|
||||||
|
for modman_segs in (("r2modmanPlus-local",), ("Thunderstore Mod Manager", "DataFolder"))
|
||||||
|
]
|
||||||
|
mod_man_roots = [pathlib.Path(f) for f in os.getenv(MODMAN_PATH_ENV, "").split(',') if f] or MODMAN_CANDIDATES
|
||||||
|
mod_man_roots = [e for e in mod_man_roots if e.is_dir()]
|
||||||
|
logging.debug(f"Using {mod_man_roots=}")
|
||||||
|
|
||||||
|
dest_base_loc = pathlib.Path(os.getenv("DEST_BASE_LOC") or repo_root_impure().joinpath("r2_profiles"))
|
||||||
|
if dest_base_loc.is_file():
|
||||||
|
raise KeyError("{dest_base_loc=} is a file, expected directory or able to recursively make dirs")
|
||||||
|
if not dry_run:
|
||||||
|
os.makedirs(dest_base_loc, exist_ok=True)
|
||||||
|
logging.debug(f"Using {dest_base_loc=}")
|
||||||
|
|
||||||
|
if mod_man_roots == []:
|
||||||
|
raise KeyError(f'No mod manager found locally, set "{MODMAN_PATH_ENV}" env or check {MODMAN_CANDIDATES}')
|
||||||
|
|
||||||
|
def profile_of(r2z_fname: pathlib.Path):
|
||||||
|
stem = r2z_fname.stem
|
||||||
|
v = stem.split("_")
|
||||||
|
if len(v) == 1:
|
||||||
|
return stem
|
||||||
|
*head, tail = v
|
||||||
|
if tail.isnumeric():
|
||||||
|
return "_".join(head)
|
||||||
|
return stem
|
||||||
|
# latest profiles (based on OS's reported mtime, disregard r2modman's stem)
|
||||||
|
raw_profiles = [
|
||||||
|
file
|
||||||
|
for file in sorted(
|
||||||
|
# flatten from both roots
|
||||||
|
[f for root in mod_man_roots for f in root.joinpath("exports").iterdir()],
|
||||||
|
key=lambda e: e.stat().st_mtime,
|
||||||
|
# dict comprehension chooses latter entry if duplicate key
|
||||||
|
reverse=False,
|
||||||
|
)
|
||||||
|
if file.is_file() and file.suffix.lower() == ".r2z"
|
||||||
|
]
|
||||||
|
profiles = { profile_of(file): file for file in raw_profiles }
|
||||||
|
logger.debug(f"{profiles=}")
|
||||||
|
if not dry_run:
|
||||||
|
for prof, r2z in profiles.items():
|
||||||
|
extract(r2z, dest_base_loc.joinpath(prof))
|
||||||
|
logger.info(f"done extracting {len(profiles)} profiles")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue