├── LICENSE ├── README.md └── ue_plugin_version_manager.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 m-ahmed-elbeskeri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unreal Engine Plugin Version Manager 2 | 3 |
6 | 7 | A simple Python utility that helps Unreal Engine plugin developers create compatible versions of their plugins for multiple engine versions (5.0.0 through 5.5.0). Save hours of manual work (or more like minutes but every little counts) with this automated tool! 8 | 9 | --- 10 | 11 | ## ✨ Features 12 | 13 | * Automatically detects `.uplugin` files in the specified folder 14 | * Creates separate plugin versions for UE **5.0.0 through 5.6.0** 15 | * Packages each version into a separate `.zip` file 16 | * Preserves all folder structures and plugin content 17 | * Works with **any** Unreal Engine plugin 18 | 19 | --- 20 | 21 | ## 📦 Requirements 22 | 23 | * Python **3.6+** 24 | * No external dependencies (uses only standard Python libraries) 25 | 26 | --- 27 | 28 | ## 🚀 Installation 29 | 30 | Clone this repository or download the script: 31 | 32 | ```bash 33 | git clone https://github.com/m-ahmed-elbeskeri/ue-plugin-version-manager.git 34 | ``` 35 | 36 | --- 37 | 38 | ## 🔧 Usage 39 | 40 | Run the script using Python: 41 | 42 | ```bash 43 | python ue_plugin_version_manager.py 44 | ``` 45 | 46 | You'll be prompted to enter the path to your plugin folder. Press Enter to use the default path. 47 | The script will then create zip files named like: 48 | 49 | ``` 50 | MyPlugin_5_0_0.zip 51 | MyPlugin_5_1_0.zip 52 | ... 53 | MyPlugin_5_5_0.zip 54 | ``` 55 | 56 | Each zip contains a version of your plugin with the correct `EngineVersion` set in the `.uplugin` file. 57 | 58 | --- 59 | 60 | ## ⚙️ How It Works 61 | 62 | 1. Locates the `.uplugin` file in your plugin folder 63 | 2. Creates a temporary copy of the entire plugin for each target engine version 64 | 3. Updates the `EngineVersion` field in each `.uplugin` file 65 | 4. Packages each modified version into its own `.zip` archive 66 | 5. Cleans up all temporary files and folders 67 | 68 | --- 69 | 70 | ## 🪯 Common Issues 71 | 72 | **Unicode Escape Error on Windows** 73 | 74 | If you get a Unicode escape error when entering a Windows path, try one of these: 75 | 76 | * Use a raw string: `r"C:\Path\To\Plugin"` 77 | * Use forward slashes: `"C:/Path/To/Plugin"` 78 | * Double the backslashes: `"C:\\Path\\To\\Plugin"` 79 | 80 | --- 81 | 82 | ## 📄 License 83 | 84 | This project is licensed under the [MIT License](LICENSE). 85 | 86 | --- 87 | 88 | ## 🤝 Contributing 89 | 90 | Contributions are welcome! Feel free to fork the repo and submit a pull request. 91 | -------------------------------------------------------------------------------- /ue_plugin_version_manager.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import zipfile 4 | import glob 5 | import shutil 6 | import re 7 | 8 | def find_uplugin_file(folder_path): 9 | """Find the first .uplugin file in the specified folder.""" 10 | uplugin_files = glob.glob(os.path.join(folder_path, "*.uplugin")) 11 | if not uplugin_files: 12 | raise FileNotFoundError(f"No .uplugin file found in {folder_path}") 13 | return uplugin_files[0] 14 | 15 | def create_version_zip(folder_path, uplugin_path, engine_version): 16 | """Create a zip file with the modified .uplugin file and all other folder contents.""" 17 | folder_name = os.path.basename(folder_path) 18 | temp_dir = f"temp_{folder_name}_{engine_version.replace('.', '_')}" 19 | 20 | # Copy the entire folder structure 21 | if os.path.exists(temp_dir): 22 | shutil.rmtree(temp_dir) 23 | shutil.copytree(folder_path, temp_dir) 24 | 25 | # Locate the uplugin file in the copied directory 26 | temp_uplugin_path = os.path.join(temp_dir, os.path.basename(uplugin_path)) 27 | 28 | # Read the uplugin file 29 | with open(temp_uplugin_path, 'r') as f: 30 | uplugin_content = f.read() 31 | 32 | # Replace the engine version using regex to preserve formatting 33 | uplugin_content = re.sub(r'"EngineVersion": "[^"]*"', f'"EngineVersion": "{engine_version}"', uplugin_content) 34 | 35 | # Write the modified uplugin file 36 | with open(temp_uplugin_path, 'w') as f: 37 | f.write(uplugin_content) 38 | 39 | # Create the zip file 40 | zip_filename = f"{folder_name}_{engine_version.replace('.', '_')}.zip" 41 | with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf: 42 | for root, _, files in os.walk(temp_dir): 43 | for file in files: 44 | file_path = os.path.join(root, file) 45 | arcname = os.path.relpath(file_path, temp_dir) 46 | zipf.write(file_path, arcname) 47 | 48 | # Clean up the temporary directory 49 | shutil.rmtree(temp_dir) 50 | 51 | return zip_filename 52 | 53 | def main(): 54 | 55 | folder_path = input("Enter the folder path (default: UE550): ") or r"UE550" 56 | 57 | try: 58 | uplugin_path = find_uplugin_file(folder_path) 59 | print(f"Found .uplugin file: {uplugin_path}") 60 | 61 | # Generate versions from 5.0.0 to 5.6.0 62 | versions = [f"5.{i}.0" for i in range(7)] 63 | 64 | for version in versions: 65 | zip_file = create_version_zip(folder_path, uplugin_path, version) 66 | print(f"Created zip file: {zip_file}") 67 | 68 | print("All zip files created successfully!") 69 | 70 | except Exception as e: 71 | print(f"Error: {e}") 72 | 73 | if __name__ == "__main__": 74 | main() 75 | --------------------------------------------------------------------------------