Skip to content

Commit

Permalink
Support distributing as Blender extension
Browse files Browse the repository at this point in the history
  • Loading branch information
lasa01 committed Nov 7, 2024
1 parent 948af81 commit 1afb17e
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 104 deletions.
46 changes: 36 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ jobs:
strategy:
matrix:
os: [macos-13, macos-latest, windows-latest]
include:
- os: macos-13
blender-install: |
brew update
brew install --cask blender
filename-match: "dist/*-macos_x64.zip"
- os: macos-latest
blender-install: |
brew update
brew install --cask blender
filename-match: "dist/*-macos_arm64.zip"
- os: windows-latest
blender-install: |
choco install blender --version=4.2.2
echo "C:\Program Files\Blender Foundation\Blender 4.2\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
filename-match: "dist/*-windows_x64.zip"
fail-fast: false
runs-on: ${{ matrix.os }}

Expand All @@ -48,16 +64,19 @@ jobs:
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Build
run: python setup.py bdist_blender_addon
- name: Rename artifact
shell: bash
run: for filename in dist/*.zip; do mv "${filename}" "${filename%.zip}-${{ runner.os }}-${{ runner.arch }}.zip"; done;
run: python setup.py build_rust --inplace --release
- name: Install Blender
run: ${{ matrix.blender-install }}
- name: Package addon into Blender extension
run: |
mkdir -p dist
blender --command extension build --source-dir ./plumber --output-dir ./dist --split-platforms
- name: Release
uses: softprops/action-gh-release@v2
with:
draft: true
fail_on_unmatched_files: true
files: dist/*.zip
files: ${{ matrix.filename-match }}

build-manylinux:
runs-on: ubuntu-latest
Expand All @@ -78,13 +97,20 @@ jobs:
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Build
run: python setup.py bdist_blender_addon
- name: Rename artifact
shell: bash
run: for filename in dist/*.zip; do mv "${filename}" "${filename%.zip}-${{ runner.os }}-${{ runner.arch }}.zip"; done;
run: python setup.py build_rust --inplace --release
- name: Install Blender
run: |
dnf install -y wget libXi
wget https://download.blender.org/release/Blender4.2/blender-4.2.3-linux-x64.tar.xz
tar -xf blender-4.2.3-linux-x64.tar.xz
echo "$PWD/blender-4.2.3-linux-x64" >> $GITHUB_PATH
- name: Package addon into Blender extension
run: |
mkdir -p dist
blender --command extension build --source-dir ./plumber --output-dir ./dist --split-platforms
- name: Release
uses: softprops/action-gh-release@v2
with:
draft: true
fail_on_unmatched_files: true
files: dist/*.zip
files: "dist/*-linux_x64.zip"
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Supported file types are `.vmf`, `.mdl`, `.vmt` and `.vtf`. For a more complete

## Requirements
- OS: Windows recommended. Linux and macOS supported.
- Blender: 2.90 or newer (tested up to 4.2).
- Blender: 2.90 or newer (up to version 1.1.1), 4.2 or newer (version 1.1.2 onwards).

## Quick start
- Make sure you are using Blender 2.90 or newer.
Expand All @@ -45,15 +45,29 @@ Supported file types are `.vmf`, `.mdl`, `.vmt` and `.vtf`. For a more complete
You can also follow a video tutorial, such as [this one](https://www.youtube.com/watch?v=jOJJzqOudw8) by ItsJustChris.
This tutorial is recorded using a beta version, but also applies to the current version.

### Blender 4.2 and above
- Make sure you are using Blender 4.2 or newer.
- Download the latest extension release from the [releases](https://github.com/lasa01/Plumber/releases) tab.
Make sure you download a file starting with `plumber-1.x.x`, not the source code.
- Do **not** extract the downloaded files.
- Open Blender and install the extension by dragging and dropping the downloaded .zip file into the Blender window.

<details>
<summary>Blender 4.1 and below</summary>

- Make sure you are using Blender 2.90 or newer.
- Download the latest addon release from the [releases](https://github.com/lasa01/Plumber/releases) tab.
Make sure you download a file starting with `plumber-v1.x.x`, not the source code.
- Download the v1.1.1 addon release from the [releases](https://github.com/lasa01/Plumber/releases/tag/v1.1.1) tab.
Make sure you download a file starting with `plumber-v1.1.1`, not the source code.
Also make sure that you downloaded the correct version for your operating system.
- Do **not** extract the downloaded files.
- Open Blender and install the addon:
![Install addon](img/install_addon.gif)

### Installing latest from source (very advanced users)
</details>

<details>
<summary>Installing latest from source (very advanced users)</summary>

Make sure the following dependencies for building the addon are installed.
The links are for Windows, for other platforms you need to figure it out yourself.
- [Python 3](https://www.python.org/downloads/) with "Add python to environment variables" selected in the installer
Expand All @@ -63,10 +77,15 @@ The links are for Windows, for other platforms you need to figure it out yoursel
- [CMake](https://cmake.org/download/)

After installing the dependencies, follow the following steps:
- Download the repository as a .zip from the green "Code" button in the top right corner and extract it somewhere (or alternatively, clone it).
- Download the repository as a .zip from the green "Code" button in the top right corner and extract it somewhere (or alternatively, clone it). Make sure you get the master branch, not the default release branch, if you want the latest changes.
- Run `pip install -r requirements-dev.txt` on a terminal.
- Run `python setup.py bdist_blender_addon`.
- The built addon will be in the `dist` directory.
- Run `python setup.py build_rust --inplace --release`.
- Figure out where your Blender is installed, and take note of the path of blender executable.
- Create the `dist` directory.
- Run `{path/to/blender} --command extension build --source-dir plumber --output-dir dist`
- The built extension will be in the `dist` directory.

</details>

## Usage

Expand Down
115 changes: 45 additions & 70 deletions plumber/__init__.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,48 @@
import platform
import os

bl_info = {
"name": "Plumber",
"author": "Lassi Säike",
"version": (1, 1, 1),
"blender": (2, 90, 0),
"location": "File > Import -> Plumber",
"description": "Imports Source Engine assets.",
"warning": "",
"tracker_url": "https://github.com/lasa01/plumber",
"category": "Import-Export",
}

version = bl_info["version"]
version_pre = bl_info["warning"]

version_str = ".".join(map(str, version))

if version_pre != "":
version_str += f"-{version_pre}"

# check if imported by setup.py or actually running in Blender
try:
from bpy.app import version as bpy_version
except ImportError:
bpy_version = None

if bpy_version is not None:
is_windows = platform.system() == "Windows"

def register():
if is_windows:
# Check if the extension module was renamed on the last unregister,
# and either rename it back or delete it if the addon was updated with a newer extension module
ext_path = os.path.join(os.path.dirname(__file__), "plumber.pyd")
unloaded_ext_path = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "plumber.pyd.unloaded"
)

if os.path.isfile(unloaded_ext_path):
if os.path.isfile(ext_path):
try:
os.remove(unloaded_ext_path)
except OSError:
print(
"[Plumber] [WARN] old files remaining, restart Blender to finish post-update clean up"
)
else:
os.rename(unloaded_ext_path, ext_path)

from . import addon

addon.register()

def unregister():
from . import addon

addon.unregister()

if is_windows:
# Rename the extension module to allow updating the addon without restarting Blender,
# since the extension module will stay open and can't be overwritten even if the addon is unloaded
ext_path = os.path.join(os.path.dirname(__file__), "plumber.pyd")
unloaded_ext_path = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "plumber.pyd.unloaded"
)

try:
os.rename(ext_path, unloaded_ext_path)
except OSError:
pass
is_windows = platform.system() == "Windows"


def register():
if is_windows:
# Check if the extension module was renamed on the last unregister,
# and either rename it back or delete it if the addon was updated with a newer extension module
ext_path = os.path.join(os.path.dirname(__file__), "plumber.pyd")
unloaded_ext_path = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "plumber.pyd.unloaded"
)

if os.path.isfile(unloaded_ext_path):
if os.path.isfile(ext_path):
try:
os.remove(unloaded_ext_path)
except OSError:
print(
"[Plumber] [WARN] old files remaining, restart Blender to finish post-update clean up"
)
else:
os.rename(unloaded_ext_path, ext_path)

from . import addon

addon.register()


def unregister():
from . import addon

addon.unregister()

if is_windows:
# Rename the extension module to allow updating the addon without restarting Blender,
# since the extension module will stay open and can't be overwritten even if the addon is unloaded
ext_path = os.path.join(os.path.dirname(__file__), "plumber.pyd")
unloaded_ext_path = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "plumber.pyd.unloaded"
)

try:
os.rename(ext_path, unloaded_ext_path)
except OSError:
pass
11 changes: 1 addition & 10 deletions plumber/addon.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import bpy
from bpy.types import Context, Menu

from . import preferences, importer, tools, benchmark, version_str
from . import preferences, importer, tools, benchmark
from .importer import ImportMdl, ImportVmf, ImportVmt, ImportVtf
from .tools import IMPORT_MT_plumber_browse

Expand Down Expand Up @@ -32,15 +32,6 @@ def menu_func_import(self: Menu, context: Context):


def register():
from . import plumber

rust_version = plumber.version()
if rust_version != version_str:
raise Exception(
f"Native code version {rust_version} does not match Python code version {version_str}. "
+ "Please restart Blender and reinstall the addon."
)

preferences.register()
importer.register()
tools.register()
Expand Down
19 changes: 19 additions & 0 deletions plumber/blender_manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
schema_version = "1.0.0"

id = "plumber"
version = "1.1.1"
name = "Plumber"
tagline = "Imports Source 1 engine maps, models, materials and textures"
maintainer = "Lassi Säike <[email protected]>"
type = "add-on"
website = "https://github.com/lasa01/Plumber"
tags = ["Import-Export"]
blender_version_min = "4.2.0"
license = ["SPDX:GPL-3.0-or-later"]
platforms = ["windows-x64", "macos-x64", "macos-arm64", "linux-x64"]

[permissions]
files = "Import/extract assets from/to disk, detect installed games"

[build]
paths_exclude_pattern = ["__pycache__/", "/.git/", "/*.zip", "/*.pyi"]
4 changes: 2 additions & 2 deletions plumber/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ class AddonPreferences(AddonPreferences):
)

def update_enable_file_browser_panel(self, context: Context):
from plumber.tools import GameFileBrowserPanel
from .tools import GameFileBrowserPanel

if not self.enable_file_browser_panel:
bpy.utils.unregister_class(GameFileBrowserPanel)
Expand All @@ -392,7 +392,7 @@ def update_enable_file_browser_panel(self, context: Context):
)

def update_enable_benchmarking(self, context: Context):
from plumber.benchmark import BenchmarkVmf
from .benchmark import BenchmarkVmf

if not self.enable_benchmarking:
bpy.utils.unregister_class(BenchmarkVmf)
Expand Down
2 changes: 1 addition & 1 deletion plumber/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
)
import bpy

from plumber.importer import (
from .importer import (
DisableCommonPanel,
GameFileImporterOperator,
GameFileImporterOperatorProps,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[build-system]
requires = ["setuptools", "setuptools-rust", "blender.distutils"]
requires = ["setuptools", "setuptools-rust", "toml"]
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fake-bpy-module-2.82
setuptools
setuptools-rust
blender.distutils
black
toml
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from setuptools import setup, find_packages, sic
from setuptools_rust import Binding, RustExtension
import toml

from plumber import version_str
with open("plumber/blender_manifest.toml", "r") as f:
manifest = toml.load(f)

version_str = manifest["version"]

rust_extension = RustExtension(
"plumber.plumber",
Expand Down
6 changes: 5 additions & 1 deletion setup_trace.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from setuptools import setup, find_packages, sic
from setuptools_rust import Binding, RustExtension
import toml

from plumber import version_str
with open("plumber/blender_manifest.toml", "r") as f:
manifest = toml.load(f)

version_str = manifest["version"]

rust_extension = RustExtension(
"plumber.plumber",
Expand Down

0 comments on commit 1afb17e

Please sign in to comment.