aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xinstaller.py25
-rwxr-xr-xmodpackman.py4
-rw-r--r--packs/jeffrey-3/pack.ini2
-rw-r--r--readme.md63
-rw-r--r--util.py27
5 files changed, 100 insertions, 21 deletions
diff --git a/installer.py b/installer.py
index deecd5b..6e2a758 100755
--- a/installer.py
+++ b/installer.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
import os
import sys
@@ -24,11 +25,16 @@ def install_forge():
Downloads and runs the Forge installer specified in pack.ini.
"""
with tempfile.TemporaryDirectory() as working_dir:
- forge_dl = requests.get(config['pack']['forge_url'], stream=True)
forge_path = os.path.join(working_dir, "forge_installer.jar")
- with open(forge_path, 'wb') as f:
- shutil.copyfileobj(forge_dl.raw, f)
- subprocess.check_output([util.find_jre(), "-jar", forge_path])
+ util.download_file(config['pack']['forge_url'], forge_path)
+ try:
+ subprocess.check_output([util.find_jre(), "-jar", forge_path])
+ except RuntimeError:
+ if sys.platform == 'win32':
+ subprocess.check_output(["start", forge_path])
+ else:
+ raise
+
def setup_forge(profile_id):
path_to_profiles = os.path.join(util.find_minecraft_directory(), "launcher_profiles.json")
@@ -59,26 +65,33 @@ def setup_forge(profile_id):
"lastVersionId": forge_game_version,
"type": "custom",
"javaArgs": config["pack"]["java_args"],
- "icon": util.generate_base64_icon(config["pack"]["icon_name"])
+ "icon": util.generate_base64_icon("icon.png")
}
profiles["profiles"][profile_id] = profile
else:
profile = profiles["profiles"][profile_id]
profile["lastVersionId"] = forge_game_version
- profile["icon"] = util.generate_base64_icon(config["pack"]["icon_name"])
+ profile["icon"] = util.generate_base64_icon("icon.png")
with open(path_to_profiles, "w") as f:
json.dump(profiles, f, indent=2)
def main():
+ # if we're in a bundle, download the latest pack data from remote source
+ if hasattr(sys, "_MEIPASS"):
+ update_self()
+
persistent_data_path = os.path.join(config["pack"]["location"], "modpackman.json")
if os.path.exists(persistent_data_path):
with open(persistent_data_path, "r") as f:
persistent_data = json.load(f)
else:
+ # this is the first time this pack is installed
pathlib.Path(config["pack"]["location"]).mkdir(parents=True, exist_ok=True)
persistent_data = {"last_forge_url": "no", "profile_id": str(uuid.uuid4()).replace('-', '')}
+ if os.path.exists(os.path.join(util.find_minecraft_directory(), 'options.txt')):
+ shutil.copyfile(os.path.join(util.find_minecraft_directory(), 'options.txt'), os.path.join(config["pack"]["location"], "options.txt"))
if config["pack"]["forge_url"] != persistent_data["last_forge_url"]:
setup_forge(persistent_data["profile_id"])
diff --git a/modpackman.py b/modpackman.py
index f578db4..18cdecc 100755
--- a/modpackman.py
+++ b/modpackman.py
@@ -45,9 +45,7 @@ def install():
else:
print(f'Installing {name} from {url}...')
print(f' ({i} of {len(pack_lock["mod_versions"])})', end='\r')
- download_obj = requests.get(url, stream=True)
- with open(mod_path, "wb") as write_file:
- shutil.copyfileobj(download_obj.raw, write_file)
+ util.download_file(url, mod_path)
print("Done!" + " " * 8)
# Remove any old mods that might be stuck in the mods folder
diff --git a/packs/jeffrey-3/pack.ini b/packs/jeffrey-3/pack.ini
index bb186fc..20ba576 100644
--- a/packs/jeffrey-3/pack.ini
+++ b/packs/jeffrey-3/pack.ini
@@ -1,8 +1,8 @@
[pack]
name = J.E.F.F.R.E.Y. 3
+pack_base_url = https://gitlab.com/1F335/modpackman/-/raw/refactor-fix/packs/jeffrey-3/
forge_url = https://files.minecraftforge.net/maven/net/minecraftforge/forge/1.16.4-35.1.13/forge-1.16.4-35.1.13-installer.jar
game_version = 1.16.4
-icon_name = icon.png
java_args = -Xmx6G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M
[mods]
diff --git a/readme.md b/readme.md
index 9149dfa..0f219bb 100644
--- a/readme.md
+++ b/readme.md
@@ -3,20 +3,67 @@
Script to update modpacks automatically
-#### To Use
+### Installation
-First, install [Python 3](https://www.python.org/downloads/) and [Git](https://git-scm.com/downloads) and add them to your `$PATH`.
-Then, run `pip install requests` to install the Python Requests module (required to run the script).
+#### For *Windows* users:
-Simply put the location of your `mods` folder in `pack-location.txt` and run `python update.py install`
+1. Close *Minecraft* and *Minecraft Launcher*.
-#### Maintenance:
+2. Download the latest installer from [the releases page](https://gitlab.com/1F335/modpackman/-/releases) and run it, completing the Forge prompt.
-To check `version.txt` modlist for updates against `mods.txt` modlist, run `python update.py check_updates`.
+3. Start *Minecraft Launcher* and launch the newly installed modpack profile.
-To automatically populate `version.txt` with the most recent versions of mods listed in `mods.txt` run `python update.py apply_updates`.
-Finally, to actually install mods from the list in `version.txt`, run `python update.py install`
+#### For other platforms:
+1. Install Git, Python 3, Java, and *Minecraft*.
+
+2. Close *Minecraft* and *Minecraft Launcher*.
+
+3. Install the Python `requests` module with `pip install requests` (or `pip install --user requests` if the first one fails).
+
+4. Clone or download this repository.
+
+5. In a shell, navigate to the directory of your desired pack (e.g. `cd packs/jeffrey-3` for the J.E.F.F.R.E.Y. 3 modpack).
+
+6. Run the installer with `python ../../installer.py`
+
+7. Start *Minecraft Launcher* and launch the newly installed modpack profile.
+
+
+### Maintenance:
+
+To select a pack to work on, navigate to its directory (e.g. `cd packs/jeffrey-3` for the J.E.F.F.R.E.Y. 3 modpack).
+
+Run `python ../../modpackman.py apply_updates` to update `pack-lock.ini` with the most recent compatible versions of every mod specified in this pack's `pack.ini`. This will also update the list of bundled config files and increment the pack version.
+
+Run `python ../../modpackman.py check_updates` to print out available updates for all the mods specified in this pack.
+
+To bypass everything except the mod downloads, run `python ../../modpackman.py install`. This will install all the mods specified in this pack's `pack-lock.ini`
***NOTE***: `check_updates` and `apply_updates` require you to have the `selenium` module installed
+
+
+### Configuration:
+
+All of the data related to specific pack is stored in its folder in `packs/`. This includes:
+ - The icon for the launcher profile (`icon.png`)
+ - The icon for the executable installer (`icon.ico`)
+ - The default mod config files (`config/`)
+ - The modpackman pack configuration (`pack.ini`)
+ - The current pack version information (`pack-lock.ini`)
+
+Note: you can create a file `local-config.ini` in this folder on your local machine that will override any specified values in `pack.ini`
+
+`pack.ini` has two sections:
+
+ - `pack`, with these options:
+ - `name`: the user-friendly name of the modpack
+ - `pack_base_url`: the web url from whence the pack's data may be retrieved
+ - `forge_url`: the download url for the forge installer for this pack. (note: this skips the Forge ads, consider supporting the project directly instead)
+ - `game_version`: the maximum *Minecraft* version to update mods to
+ - `java_args`: Java arguments to be added to the pack launcher profile when it is created.
+
+ - `mods`, which is a collection of `mod_name = download_url` pairs. For mods hosted on curseforge, the download url is the project's homepage url.
+
+
diff --git a/util.py b/util.py
index 0167bbc..d76eb76 100644
--- a/util.py
+++ b/util.py
@@ -9,7 +9,7 @@ import urllib.parse
import multiprocessing
import pathlib
import base64
-from configparser import ConfigParser
+from configparser import RawConfigParser
import requests
@@ -19,7 +19,7 @@ def load_config():
Load configuarion from pack and local configuration files
Fill in reasonable defaults where applicable.
"""
- config_p = ConfigParser()
+ config_p = RawConfigParser()
config_p.read(["pack.ini", "local-config.ini"])
config = config_p._sections
config["pack"]["sanitized_name"] = sanitize_text(config["pack"]["name"])
@@ -44,8 +44,21 @@ def update_self():
in order to update to the latest version. Will overwrite any existing pack.ini and other
config files, so be careful!
"""
+ global config
+
+ base_url = config["pack"]["pack_base_url"].strip("/") + "/"
+ download_file(base_url + "pack.ini", "pack.ini")
+ download_file(base_url + "pack-lock.ini", "pack-lock.ini")
+ download_file(base_url + "icon.png", "icon.png")
+
+ pack_lock = RawConfigParser()
+ pack_lock.read(["pack-lock.ini"])
+ for path in pack_lock["global"]["config_files"].split(","):
+ if not path:
+ continue
+ download_file(f"{base_url}config/{path}", os.path.join("config", path))
- raise NotImplementedError()
+ config = load_config()
def find_minecraft_directory():
@@ -78,6 +91,14 @@ def find_jre():
return "C:\\Program Files (x86)\\Minecraft Launcher\\runtime\\jre-x64\\java.exe"
raise RuntimeError("Unable to detect an installed JRE. Please install Java in order to use modpackman.")
+def download_file(url, destination):
+ """
+ given a url, performs a requests request to get the remote object
+ and write it to destination
+ """
+ with open(destination, "wb") as f:
+ dl = requests.get(url, stream=True)
+ shutil.copyfileobj(dl.raw, f)
# take a string and only keep filename-friendly parts
def sanitize_text(text):