Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/scripts/extract_changelog_section.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""Extract a single version's section from a CHANGELOG.md for use as GitHub release notes.

Looks for a Markdown heading line starting with "## " that contains the given
version (e.g. "v1.2.0"), followed by a non-digit/non-dot character or end of
line (so "v1.2.0" doesn't accidentally match "v1.2.0-rc1" or "v1.2.01"). Prints
everything between that heading and the next "## " heading (or EOF), with
leading/trailing blank lines stripped.
"""

import argparse
import re
import sys


def extract_section(changelog_text: str, version: str) -> str | None:
version_re = re.compile(re.escape(version) + r"([^0-9.]|$)")
lines = changelog_text.splitlines()

start = None
end = len(lines)
for i, line in enumerate(lines):
if not line.startswith("## "):
continue
if start is None:
if version_re.search(line):
start = i + 1
continue
end = i
break

if start is None:
return None

section_lines = lines[start:end]
while section_lines and not section_lines[0].strip():
section_lines.pop(0)
while section_lines and not section_lines[-1].strip():
section_lines.pop()
return "\n".join(section_lines)


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--changelog", required=True, help="Path to CHANGELOG.md")
parser.add_argument("--version", required=True, help="Version to extract, e.g. v1.2.0 or 1.2.0")
parser.add_argument("--product-name", required=True, help="Display name used in the error message, e.g. 'Simple Collider'")
parser.add_argument("--output", required=True, help="Path to write the extracted section to")
args = parser.parse_args()

version = args.version[1:] if args.version.startswith("v") else args.version

with open(args.changelog, "r", encoding="utf-8") as f:
text = f.read()

section = extract_section(text, version)
if not section:
print(
f"::error::No CHANGELOG.md section found for version {version} "
f"(tag v{version}). Add a '## {args.product_name} v{version}' section before tagging.",
file=sys.stderr,
)
return 1

with open(args.output, "w", encoding="utf-8") as f:
f.write(section + "\n")
return 0


if __name__ == "__main__":
sys.exit(main())
71 changes: 71 additions & 0 deletions .github/workflows/BuildRelease.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Build Release

on:
push:
tags: ["v[0-9]+.[0-9]+.[0-9]+"]

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
path: ${{ github.event.repository.name }}

- name: Check manifest version matches tag
run: |
tag_version="${{ github.ref_name }}"
tag_version="${tag_version#v}"
manifest_version=$(python3 -c "import tomllib; print(tomllib.load(open('blender_manifest.toml','rb'))['version'])")
if [ "$tag_version" != "$manifest_version" ]; then
echo "::error::Tag v$tag_version != blender_manifest.toml version $manifest_version"
exit 1
fi
working-directory: ${{ github.event.repository.name }}

- name: Cache Blender 4.2
id: cache-blender
uses: actions/cache@v4
with:
path: blender-download
key: blender-4.2-ubuntu-latest

- name: Download Blender 4.2
if: steps.cache-blender.outputs.cache-hit != 'true'
run: |
mkdir -p blender-download
pip install blender-downloader
blender-downloader 4.2 --extract --quiet --output-directory blender-download

- name: Locate Blender executable
id: blender
run: |
EXE=$(find blender-download -type f -iname blender | head -n 1)
if [ -z "$EXE" ]; then
echo "Could not find a Blender executable under blender-download/" >&2
exit 1
fi
chmod +x "$EXE"
echo "executable=$EXE" >> "$GITHUB_OUTPUT"

- name: Validate extension manifest
run: |
"${{ steps.blender.outputs.executable }}" --command extension validate ${{ github.event.repository.name }}

- name: Build extension zip
run: |
mkdir -p dist
"${{ steps.blender.outputs.executable }}" --command extension build --source-dir ${{ github.event.repository.name }} --output-dir dist

- name: Extract release notes from CHANGELOG.md
run: |
python3 ${{ github.event.repository.name }}/.github/scripts/extract_changelog_section.py \
--changelog ${{ github.event.repository.name }}/CHANGELOG.md \
--version "${{ github.ref_name }}" \
--product-name "Simple Collider" \
--output release_notes.md

- name: Create GitHub release
run: gh release create "${{ github.ref_name }}" --notes-file release_notes.md dist/*.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50 changes: 32 additions & 18 deletions .github/workflows/TestBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,47 @@ jobs:
with:
path: ${{ github.event.repository.name }}

- name: Read version from blender_manifest.toml
id: version
- name: Cache Blender 4.2
id: cache-blender
uses: actions/cache@v4
with:
path: blender-download
key: blender-4.2-ubuntu-latest

- name: Download Blender 4.2
if: steps.cache-blender.outputs.cache-hit != 'true'
run: |
mkdir -p blender-download
pip install blender-downloader
blender-downloader 4.2 --extract --quiet --output-directory blender-download

- name: Locate Blender executable
id: blender
run: |
VERSION=$(python3 -c "import tomllib; f=open('${{ github.event.repository.name }}/blender_manifest.toml','rb'); print(tomllib.load(f)['version'])")
echo "version=$VERSION" >> $GITHUB_OUTPUT
EXE=$(find blender-download -type f -iname blender | head -n 1)
if [ -z "$EXE" ]; then
echo "Could not find a Blender executable under blender-download/" >&2
exit 1
fi
chmod +x "$EXE"
echo "executable=$EXE" >> "$GITHUB_OUTPUT"

- name: Set short SHA
id: vars
run: echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT

- name: Prepare add-on folder
- name: Validate extension manifest
run: |
"${{ steps.blender.outputs.executable }}" --command extension validate ${{ github.event.repository.name }}

- name: Build extension zip
run: |
mkdir -p staging/simple_collider
rsync -a \
--exclude='.git' \
--exclude='.*' \
--exclude='tests' \
--exclude='venv' \
--exclude='__pycache__' \
--exclude='*.pyc' \
--exclude='CHANGELOG.md' \
--exclude='MANUAL_QA_CHECKLIST.md' \
${{ github.event.repository.name }}/ staging/simple_collider/
mkdir -p dist
"${{ steps.blender.outputs.executable }}" --command extension build --source-dir ${{ github.event.repository.name }} --output-dir dist

- name: Upload zip as artifact
uses: actions/upload-artifact@v4
with:
name: simple_collider_${{ steps.version.outputs.version }}_${{ steps.vars.outputs.short_sha }}
path: staging/
name: ${{ github.event.repository.name }}_${{ steps.vars.outputs.short_sha }}
path: dist/
retention-days: 7
54 changes: 0 additions & 54 deletions .github/workflows/main.yml

This file was deleted.

11 changes: 6 additions & 5 deletions MANUAL_QA_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ Blender version tested: ______ OS: ______ Date: ______
temp mesh/collection left behind.
- [ ] Run Auto Convex (V-HACD) on a simple mesh with default settings →
produces one or more convex hull colliders without hanging Blender.
- [ ] Run Auto Convex (CoACD, BETA) once with default settings → completes
and produces hulls (acceptable to be rougher — it's BETA).
- [ ] Run Auto Convex (CoACD, High Precision) once with default settings →
completes and produces hulls without freezing Blender (can take longer
than V-HACD — that's expected).
- [ ] Convert to Collider on a plain mesh object → object becomes a collider
in place; Convert to Mesh on a collider → reverses it back to a normal
render mesh.
Expand Down Expand Up @@ -182,10 +183,10 @@ Blender version tested: ______ OS: ______ Date: ______
is hidden entirely and prefs show an unsupported-platform message instead
of a broken button.

### 5. Auto Convex — CoACD (BETA)
### 5. Auto Convex — CoACD (High Precision)

- [ ] Confirm the operator/label/prefs all clearly read "BETA" so testers
don't hold it to the same bar as V-HACD.
- [ ] Confirm the operator/label/prefs all clearly read "High Precision" (not
"BETA") and communicate the speed tradeoff vs. V-HACD.
- [ ] Enable `coacd_decimate` with a low `coacd_maxHullVertCount` → each
hull actually gets vertex-limited (check per-hull vert counts before/
after); a hull whose decimation fails reports "CoACD hull decimation
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Simple Collider is a Blender addon for creating physics colliders for games and

* Collider shapes: Box, Sphere, Cylinder, Capsule, Convex Hull, K-DOP (10/18/26), Minimum/Aligned Bounding Box,
Re-meshed (voxel remesh), and full-detail Mesh.
* Auto Convex decomposition using V-HACD, plus an alternative CoACD backend (BETA).
* Auto Convex decomposition using V-HACD, plus an alternative CoACD backend for higher-precision (but slower)
results.
* Validation Checks (BETA): scan the scene or selection for missing colliders, non-manifold geometry, flipped
normals, oversized triangle counts, mismatched bounding boxes, naming/parenting conventions, missing physics
materials, and more - configurable per-check in preferences.
Expand Down
Loading
Loading