Compare commits
16 Commits
patch-release
...
v2.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 598065f255 | |||
| c471afaee4 | |||
| 0228fcfd92 | |||
| 8fc3c1b915 | |||
| 74c1e86c32 | |||
| 19f10a4486 | |||
| 8255b1f465 | |||
| 625ff5ec69 | |||
| ccd759da45 | |||
| a708da8836 | |||
| d2156c6d1a | |||
| 5b34f8b96f | |||
| b4ce7453c3 | |||
| 594a0ce84d | |||
| cc584c3251 | |||
| 3ca2ff3c0f |
@@ -0,0 +1,122 @@
|
||||
name: Build Artifacts
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
platform:
|
||||
description: 'Platform to build'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- windows
|
||||
- linux
|
||||
- android
|
||||
- all
|
||||
version:
|
||||
description: 'Version tag (optional)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
name: Build Windows
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
if: github.event.inputs.platform == 'windows' || github.event.inputs.platform == 'all'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Export Windows
|
||||
run: |
|
||||
godot --headless --export-release "Windows Desktop" build/tekton_armageddon_${{ github.event.inputs.version || 'dev' }}_windows.exe
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-windows-${{ github.event.inputs.version || 'dev' }}
|
||||
path: build/tekton_armageddon_${{ github.event.inputs.version || 'dev' }}_windows.exe
|
||||
retention-days: 30
|
||||
|
||||
build-linux:
|
||||
name: Build Linux
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
if: github.event.inputs.platform == 'linux' || github.event.inputs.platform == 'all'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Export Linux
|
||||
run: |
|
||||
godot --headless --export-release "Linux/X11" build/tekton_armageddon_${{ github.event.inputs.version || 'dev' }}_linux.x86_64
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-linux-${{ github.event.inputs.version || 'dev' }}
|
||||
path: build/tekton_armageddon_${{ github.event.inputs.version || 'dev' }}_linux.x86_64
|
||||
retention-days: 30
|
||||
|
||||
build-android:
|
||||
name: Build Android
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
if: github.event.inputs.platform == 'android' || github.event.inputs.platform == 'all'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v3
|
||||
with:
|
||||
api-level: 34
|
||||
ndk-version: r26c
|
||||
cmdline-tools-version: latest
|
||||
|
||||
- name: Export Android
|
||||
run: |
|
||||
godot --headless --export-release "Android" build/tekton_dash_armageddon_${{ github.event.inputs.version || 'dev' }}.apk
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-android-${{ github.event.inputs.version || 'dev' }}
|
||||
path: build/tekton_dash_armageddon_${{ github.event.inputs.version || 'dev' }}.apk
|
||||
retention-days: 30
|
||||
@@ -0,0 +1,171 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, experimental, patch-release]
|
||||
pull_request:
|
||||
branches: [main, experimental, patch-release]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# Install Godot headless dependencies
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libvulkan1 libx11-6 libxcursor1 libxi6 libxrandr2 libxinerama1 libxi6 libxxf86vm1 libgl1
|
||||
|
||||
- name: Run GUT tests
|
||||
run: |
|
||||
godot --headless -d --path . -s addons/gut/gut_cmdln.gd
|
||||
|
||||
export-windows:
|
||||
name: Export Windows
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
needs: test
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Export Windows
|
||||
run: |
|
||||
godot --headless --export-release "Windows Desktop" build/tekton_armageddon_windows.exe
|
||||
|
||||
- name: Upload Windows artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-windows
|
||||
path: build/tekton_armageddon_windows.exe
|
||||
retention-days: 7
|
||||
|
||||
export-linux:
|
||||
name: Export Linux
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
needs: test
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Export Linux
|
||||
run: |
|
||||
godot --headless --export-release "Linux/X11" build/tekton_armageddon_linux.x86_64
|
||||
|
||||
- name: Upload Linux artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-linux
|
||||
path: build/tekton_armageddon_linux.x86_64
|
||||
retention-days: 7
|
||||
|
||||
export-android:
|
||||
name: Export Android
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
needs: test
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v3
|
||||
with:
|
||||
api-level: 34
|
||||
ndk-version: r26c
|
||||
cmdline-tools-version: latest
|
||||
|
||||
- name: Export Android
|
||||
run: |
|
||||
godot --headless --export-release "Android" build/tekton_dash_armageddon.apk
|
||||
|
||||
- name: Upload Android artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-android
|
||||
path: build/tekton_dash_armageddon.apk
|
||||
retention-days: 7
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
needs: [export-windows, export-linux, export-android]
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download Windows artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: tekton-windows
|
||||
path: artifacts/windows
|
||||
|
||||
- name: Download Linux artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: tekton-linux
|
||||
path: artifacts/linux
|
||||
|
||||
- name: Download Android artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: tekton-android
|
||||
path: artifacts/android
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
artifacts/windows/tekton_armageddon_windows.exe
|
||||
artifacts/linux/tekton_armageddon_linux.x86_64
|
||||
artifacts/android/tekton_dash_armageddon.apk
|
||||
generate_release_notes: true
|
||||
@@ -0,0 +1,83 @@
|
||||
name: Deploy Patch
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Patch version (e.g., 2.4.2)'
|
||||
required: true
|
||||
type: string
|
||||
notes:
|
||||
description: 'Release notes'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-patch:
|
||||
name: Build Patch
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Run patch build script
|
||||
run: |
|
||||
python3 patch_version.py ${{ github.event.inputs.version }} "${{ github.event.inputs.notes }}"
|
||||
|
||||
- name: Export Windows patch
|
||||
run: |
|
||||
godot --headless --export-release "Windows Desktop" build/tekton_armageddon_patch_windows.exe
|
||||
|
||||
- name: Export Linux patch
|
||||
run: |
|
||||
godot --headless --export-release "Linux/X11" build/tekton_armageddon_patch_linux.x86_64
|
||||
|
||||
- name: Upload patch artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-patch-${{ github.event.inputs.version }}
|
||||
path: |
|
||||
build/tekton_armageddon_patch_windows.exe
|
||||
build/tekton_armageddon_patch_linux.x86_64
|
||||
retention-days: 30
|
||||
|
||||
deploy-patch:
|
||||
name: Deploy Patch
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
needs: build-patch
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download patch artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: tekton-patch-${{ github.event.inputs.version }}
|
||||
path: artifacts/patch
|
||||
|
||||
- name: Create patch release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: patch-${{ github.event.inputs.version }}
|
||||
name: "Patch ${{ github.event.inputs.version }}"
|
||||
body: |
|
||||
${{ github.event.inputs.notes }}
|
||||
files: |
|
||||
artifacts/patch/tekton_armageddon_patch_windows.exe
|
||||
artifacts/patch/tekton_armageddon_patch_linux.x86_64
|
||||
prerelease: true
|
||||
@@ -0,0 +1,109 @@
|
||||
name: Test Suite
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, experimental, patch-release]
|
||||
pull_request:
|
||||
branches: [main, experimental, patch-release]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
name: Unit Tests (GUT)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libvulkan1 libx11-6 libxcursor1 libxi6 libxrandr2 libxinerama1 libxi6 libxxf86vm1 libgl1
|
||||
|
||||
- name: Run GUT tests
|
||||
run: |
|
||||
godot --headless -d --path . -s addons/gut/gut_cmdln.gd
|
||||
|
||||
integration-tests:
|
||||
name: Integration Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Install export templates
|
||||
run: |
|
||||
mkdir -v -p ~/.local/share/godot/export_templates/4.6.stable
|
||||
wget -q https://github.com/godotengine/godot-builds/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz
|
||||
unzip -q Godot_v4.6-stable_export_templates.tpz -d ~/.local/share/godot/export_templates/4.6.stable
|
||||
|
||||
- name: Export headless server for integration tests
|
||||
run: |
|
||||
godot --headless --export-release "Linux/X11" build/tekton_server.x86_64
|
||||
|
||||
- name: Run integration tests
|
||||
run: |
|
||||
# Start server in background
|
||||
./build/tekton_server.x86_64 --headless --port 7777 &
|
||||
SERVER_PID=$!
|
||||
sleep 5
|
||||
|
||||
# Run client tests against server
|
||||
godot --headless -d --path . -s addons/gut/gut_cmdln.gd --select=test_integration
|
||||
|
||||
# Cleanup
|
||||
kill $SERVER_PID
|
||||
|
||||
lint:
|
||||
name: Code Style Check
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: firebelley/godot-action@v3
|
||||
with:
|
||||
godot-version: '4.6'
|
||||
engine-type: standard
|
||||
|
||||
- name: Check GDScript formatting
|
||||
run: |
|
||||
godot --headless --check-only -s scripts/lint.gd || true
|
||||
# Note: GDScript doesn't have a built-in formatter; this checks syntax only
|
||||
|
||||
security-scan:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy results to GitHub Security
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Upload PCK to Gitea Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: barichello/godot-ci:4.3
|
||||
steps:
|
||||
- name: Checkout
|
||||
run: |
|
||||
git clone https://git.klud.top/danchie/tekton.git .
|
||||
git checkout ${{ github.ref_name }}
|
||||
|
||||
- name: Build PCK
|
||||
run: godot --headless -s tools/build_patch.gd
|
||||
|
||||
- name: Upload PCK to Release
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: token ${{ secrets.TEKTON_RELEASE_TOKEN }}" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F "attachment=@patch.pck" \
|
||||
"https://git.klud.top/api/v1/repos/danchie/tekton/releases/tags/${{ github.ref_name }}"
|
||||
|
||||
- name: Upload version.json to Release
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: token ${{ secrets.TEKTON_RELEASE_TOKEN }}" \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-F "attachment=@assets/data/version.json" \
|
||||
"https://git.klud.top/api/v1/repos/danchie/tekton/releases/tags/${{ github.ref_name }}"
|
||||
@@ -1,128 +0,0 @@
|
||||
name: Build and Export
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version to build (e.g., 2.4.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: chickensoft-games/setup-godot@v1
|
||||
with:
|
||||
version: '4.6.0'
|
||||
use-dotnet: false
|
||||
|
||||
- name: Setup Export Templates
|
||||
run: |
|
||||
TEMPLATES_DIR=~/.local/share/godot/export_templates/4.6.stable
|
||||
mkdir -p "$TEMPLATES_DIR"
|
||||
wget -q https://github.com/godotengine/godot/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz -O templates.tpz
|
||||
unzip -q templates.tpz -d "$TEMPLATES_DIR"
|
||||
mv "$TEMPLATES_DIR/templates/"* "$TEMPLATES_DIR/"
|
||||
rmdir "$TEMPLATES_DIR/templates"
|
||||
|
||||
- name: Export Windows Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
godot --headless --export-release "Windows Desktop" build/tekton_armageddon_windows.exe
|
||||
|
||||
- name: Zip Windows Build
|
||||
run: cd build && zip tekton_armageddon_windows.zip tekton_armageddon_windows.exe
|
||||
|
||||
- name: Upload Windows Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-build
|
||||
path: build/tekton_armageddon_windows.zip
|
||||
retention-days: 30
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: chickensoft-games/setup-godot@v1
|
||||
with:
|
||||
version: '4.6.0'
|
||||
use-dotnet: false
|
||||
|
||||
- name: Setup Export Templates
|
||||
run: |
|
||||
TEMPLATES_DIR=~/.local/share/godot/export_templates/4.6.stable
|
||||
mkdir -p "$TEMPLATES_DIR"
|
||||
wget -q https://github.com/godotengine/godot/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz -O templates.tpz
|
||||
unzip -q templates.tpz -d "$TEMPLATES_DIR"
|
||||
mv "$TEMPLATES_DIR/templates/"* "$TEMPLATES_DIR/"
|
||||
rmdir "$TEMPLATES_DIR/templates"
|
||||
|
||||
- name: Export Linux Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
godot --headless --export-release "Linux/X11" build/tekton_armageddon_linux.x86_64
|
||||
|
||||
- name: Zip Linux Build
|
||||
run: cd build && zip tekton_armageddon_linux.zip tekton_armageddon_linux.x86_64
|
||||
|
||||
- name: Upload Linux Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-build
|
||||
path: build/tekton_armageddon_linux.zip
|
||||
retention-days: 30
|
||||
|
||||
create-release:
|
||||
needs: [build-windows, build-linux]
|
||||
runs-on: ubuntu-latest
|
||||
if: always() && startsWith(github.ref, 'refs/tags/')
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Extract Version
|
||||
id: version
|
||||
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download All Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
windows-build/tekton_armageddon_windows.zip
|
||||
linux-build/tekton_armageddon_linux.zip
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Mirror to tekton-updates
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
run: |
|
||||
gh release create "v${{ steps.version.outputs.version }}" \
|
||||
--repo "${{ github.actor }}/tekton-updates" \
|
||||
--title "v${{ steps.version.outputs.version }}" \
|
||||
--notes "Mirror of https://github.com/${{ github.repository }}/releases/tag/v${{ steps.version.outputs.version }}" \
|
||||
"windows-build/tekton_armageddon_windows.zip#Windows" \
|
||||
"linux-build/tekton_armageddon_linux.zip#Linux"
|
||||
@@ -1,177 +0,0 @@
|
||||
name: Build Platform Artifacts
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version to build (e.g., 2.4.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- name: Windows
|
||||
preset: "Windows Desktop"
|
||||
extension: exe
|
||||
- name: Linux
|
||||
preset: "Linux/X11"
|
||||
extension: x86_64
|
||||
- name: Android
|
||||
preset: "Android"
|
||||
extension: apk
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Godot
|
||||
uses: chickensoft-games/setup-godot@v1
|
||||
with:
|
||||
version: '4.6.0'
|
||||
use-dotnet: false
|
||||
|
||||
- name: Setup Export Templates
|
||||
run: |
|
||||
TEMPLATES_DIR=~/.local/share/godot/export_templates/4.6.stable
|
||||
mkdir -p "$TEMPLATES_DIR"
|
||||
wget -q https://github.com/godotengine/godot/releases/download/4.6-stable/Godot_v4.6-stable_export_templates.tpz -O templates.tpz
|
||||
unzip -q templates.tpz -d "$TEMPLATES_DIR"
|
||||
mv "$TEMPLATES_DIR/templates/"* "$TEMPLATES_DIR/"
|
||||
rmdir "$TEMPLATES_DIR/templates"
|
||||
|
||||
- name: Setup Android SDK (Android only)
|
||||
if: matrix.platform.name == 'Android'
|
||||
uses: android-actions/setup-android@v3
|
||||
|
||||
- name: Extract Version
|
||||
id: version
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||
VERSION="${{ inputs.version }}"
|
||||
else
|
||||
VERSION="${GITHUB_REF#refs/tags/v}"
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Building version: $VERSION"
|
||||
|
||||
- name: Create Build Directory
|
||||
run: mkdir -p build
|
||||
|
||||
- name: Export Game
|
||||
run: |
|
||||
godot --headless --export-release "${{ matrix.platform.preset }}" \
|
||||
"build/tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.${{ matrix.platform.extension }}"
|
||||
|
||||
- name: Generate Checksums
|
||||
run: |
|
||||
cd build
|
||||
sha256sum tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.${{ matrix.platform.extension }} \
|
||||
> tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.sha256
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-${{ matrix.platform.name }}-v${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
build/tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.${{ matrix.platform.extension }}
|
||||
build/tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.sha256
|
||||
retention-days: 90
|
||||
compression-level: 0
|
||||
|
||||
- name: Create Release Asset
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
build/tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.${{ matrix.platform.extension }}
|
||||
build/tekton_armageddon_${{ matrix.platform.name }}_v${{ steps.version.outputs.version }}.sha256
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-patch:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Godot
|
||||
uses: chickensoft-games/setup-godot@v1
|
||||
with:
|
||||
version: '4.6.0'
|
||||
use-dotnet: false
|
||||
|
||||
- name: Extract Version
|
||||
id: version
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||
VERSION="${{ inputs.version }}"
|
||||
else
|
||||
VERSION="${GITHUB_REF#refs/tags/v}"
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate Changed Files List
|
||||
run: |
|
||||
find scripts/ scenes/ assets/ -type f > changed_files.txt
|
||||
echo "Patching $(wc -l < changed_files.txt) files"
|
||||
|
||||
- name: Build Patch PCK
|
||||
run: godot --headless -s tools/build_patch.gd
|
||||
|
||||
- name: Generate Patch Checksum
|
||||
run: |
|
||||
sha256sum patch.pck > patch.pck.sha256
|
||||
|
||||
- name: Upload Patch Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tekton-patch-v${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
patch.pck
|
||||
patch.pck.sha256
|
||||
retention-days: 90
|
||||
|
||||
- name: Push to Updates Repository
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: dmnemec/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
with:
|
||||
source_file: 'patch.pck'
|
||||
destination_repo: '${{ github.actor }}/tekton-updates'
|
||||
destination_folder: 'v${{ steps.version.outputs.version }}'
|
||||
user_email: 'action@github.com'
|
||||
user_name: 'PatchBot'
|
||||
commit_message: '[AUTO] Release v${{ steps.version.outputs.version }} patch'
|
||||
|
||||
- name: Push Checksum to Updates Repository
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: dmnemec/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
with:
|
||||
source_file: 'patch.pck.sha256'
|
||||
destination_repo: '${{ github.actor }}/tekton-updates'
|
||||
destination_folder: 'v${{ steps.version.outputs.version }}'
|
||||
user_email: 'action@github.com'
|
||||
user_name: 'PatchBot'
|
||||
commit_message: '[AUTO] Release v${{ steps.version.outputs.version }} checksum'
|
||||
@@ -1,130 +0,0 @@
|
||||
name: Build and Release Patch PCK
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'patch-release'
|
||||
paths:
|
||||
- 'scripts/**'
|
||||
- 'scenes/**'
|
||||
- 'assets/**'
|
||||
- 'CHANGELOG_DRAFT.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-deploy-patch:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# ── 1. Auto-generate version.json from CHANGELOG_DRAFT.md ────────────
|
||||
- name: Generate Version JSON & Bump Version
|
||||
run: python3 tools/generate_version_json.py
|
||||
|
||||
# ── 2. Commit bumped files back to the repo ───────────────────────────
|
||||
- name: Commit Version Bump
|
||||
run: |
|
||||
git config user.name "PatchBot"
|
||||
git config user.email "action@github.com"
|
||||
git add assets/data/version.json project.godot CHANGELOG_DRAFT.md
|
||||
git diff --staged --quiet || git commit -m "[AUTO] Version bump & changelog update"
|
||||
git push
|
||||
|
||||
# ── 3. Detect changed files for patch PCK ────────────────────────────
|
||||
- name: Generate Changed Files List
|
||||
run: |
|
||||
git diff --name-only HEAD^ HEAD -- 'scripts/**' 'scenes/**' 'assets/**' > changed_files.txt
|
||||
echo "Files to patch:"
|
||||
cat changed_files.txt
|
||||
|
||||
# ── 4. Build patch.pck ────────────────────────────────────────────────
|
||||
- name: Setup Godot
|
||||
uses: chickensoft-games/setup-godot@v1
|
||||
with:
|
||||
version: '4.6.0'
|
||||
use-dotnet: false
|
||||
|
||||
- name: Run Build Patch Script
|
||||
run: godot --headless -s tools/build_patch.gd
|
||||
|
||||
# ── 5. Generate checksums ─────────────────────────────────────────────────
|
||||
- name: Generate Checksums
|
||||
run: |
|
||||
sha256sum patch.pck > patch.pck.sha256
|
||||
sha256sum assets/data/version.json > version.json.sha256
|
||||
|
||||
# ── 6. Upload artifacts to GitHub ─────────────────────────────────────────
|
||||
- name: Upload Patch Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: patch-pck-${{ github.sha }}
|
||||
path: |
|
||||
patch.pck
|
||||
patch.pck.sha256
|
||||
retention-days: 90
|
||||
|
||||
- name: Upload Version Manifest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: version-manifest-${{ github.sha }}
|
||||
path: |
|
||||
assets/data/version.json
|
||||
version.json.sha256
|
||||
retention-days: 90
|
||||
|
||||
# ── 7. Push patch.pck to public repo ─────────────────────────────────────
|
||||
- name: Push patch.pck to Public Repository
|
||||
uses: dmnemec/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
with:
|
||||
source_file: 'patch.pck'
|
||||
destination_repo: '${{ github.actor }}/tekton-updates'
|
||||
destination_folder: 'latest'
|
||||
user_email: 'action@github.com'
|
||||
user_name: 'PatchBot'
|
||||
commit_message: '[AUTO] Pushed new patch.pck'
|
||||
|
||||
- name: Push patch checksum to Public Repository
|
||||
uses: dmnemec/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
with:
|
||||
source_file: 'patch.pck.sha256'
|
||||
destination_repo: '${{ github.actor }}/tekton-updates'
|
||||
destination_folder: 'latest'
|
||||
user_email: 'action@github.com'
|
||||
user_name: 'PatchBot'
|
||||
commit_message: '[AUTO] Pushed patch checksum'
|
||||
|
||||
# ── 8. Push version.json to public repo ──────────────────────────────────
|
||||
- name: Push version.json to Public Repository
|
||||
uses: dmnemec/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
with:
|
||||
source_file: 'assets/data/version.json'
|
||||
destination_repo: '${{ github.actor }}/tekton-updates'
|
||||
destination_folder: 'latest'
|
||||
user_email: 'action@github.com'
|
||||
user_name: 'PatchBot'
|
||||
commit_message: '[AUTO] Pushed new version.json'
|
||||
|
||||
- name: Push version checksum to Public Repository
|
||||
uses: dmnemec/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PUBLIC_REPO_PAT }}
|
||||
with:
|
||||
source_file: 'version.json.sha256'
|
||||
destination_repo: '${{ github.actor }}/tekton-updates'
|
||||
destination_folder: 'latest'
|
||||
user_email: 'action@github.com'
|
||||
user_name: 'PatchBot'
|
||||
commit_message: '[AUTO] Pushed version checksum'
|
||||
@@ -1,59 +0,0 @@
|
||||
name: Automated Testing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- 'feature/**'
|
||||
- 'patch-release'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Godot
|
||||
uses: chickensoft-games/setup-godot@v1
|
||||
with:
|
||||
version: '4.6.0'
|
||||
use-dotnet: false
|
||||
|
||||
- name: Verify GUT Installation
|
||||
run: |
|
||||
if [ ! -d "addons/gut" ]; then
|
||||
echo "ERROR: GUT addon not found at addons/gut"
|
||||
exit 1
|
||||
fi
|
||||
echo "GUT addon found"
|
||||
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
godot --headless --path . -s res://addons/gut/gut_cmdln.gd \
|
||||
-gdir=res://tests/ \
|
||||
-gexit \
|
||||
-glog=2
|
||||
|
||||
- name: Check Test Results
|
||||
if: failure()
|
||||
run: |
|
||||
echo "Tests failed. Check logs above for details."
|
||||
exit 1
|
||||
|
||||
- name: Upload Test Reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports
|
||||
path: test_reports/
|
||||
retention-days: 30
|
||||
@@ -4,7 +4,10 @@
|
||||
.agent/
|
||||
_daily_basis/
|
||||
_daily_changes/
|
||||
tools/gitea-kanban
|
||||
build/
|
||||
label_mapping.json
|
||||
milestone_mapping.json
|
||||
|
||||
/android/
|
||||
.tmp
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Cloning from any tailnet machine
|
||||
|
||||
## Prerequisites
|
||||
- The remote machine must be on your tailnet (registered + can ping `100.85.x.x`)
|
||||
- You must have an account on the Gitea instance (`http://git.klud.top`)
|
||||
- You must have an SSH key on the remote machine (`ssh-keygen` if you don't)
|
||||
|
||||
## Step 1: Add your SSH key to Gitea
|
||||
1. Open `http://git.klud.top/user/settings/keys` in browser
|
||||
2. Paste the content of `~/.ssh/id_ed25519.pub` (or `id_rsa.pub`)
|
||||
3. Click "Add Key"
|
||||
|
||||
## Step 2: Test SSH reachability
|
||||
```bash
|
||||
ssh -T git@thunderobot -p 222
|
||||
# Expected output: "Hello from Gitea!\n\nPlease come over!"
|
||||
# If asked about fingerprint, type "yes" and press Enter
|
||||
```
|
||||
|
||||
## Step 3: Clone a repo
|
||||
```bash
|
||||
# Using tea CLI
|
||||
tea repos clone --git-protocol ssh danchie/tekton
|
||||
|
||||
# Or plain git
|
||||
git clone git@thunderobot:222/danchie/tekton.git
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- `ssh: connect to host thunderobot port 222: Connection refused`
|
||||
→ Ensure the remote machine has `tailscale ping thunderobot` resolving to `100.93.226.13`
|
||||
→ Ensure the host's port `222` is reachable from the remote (it's bound to `0.0.0.0:222` in Docker)
|
||||
|
||||
- `Permission denied (publickey)`
|
||||
→ Your SSH key wasn't added via Gitea web UI
|
||||
→ Run `ssh-add ~/.ssh/id_ed25519` if you use an agent
|
||||
|
||||
- `Host key verification failed`
|
||||
→ Run `ssh -T git@thunderobot -p 222` interactively once to accept the fingerprint
|
||||
|
||||
## HTTPS is disabled
|
||||
`DISABLE_HTTP_GIT = true` is set on the server. All clones MUST use SSH.
|
||||
If you need to fetch via HTTPS for CI or other non-ssh environments, this must be remapped.
|
||||
@@ -1,141 +1,25 @@
|
||||
# Tekton Dash Armageddon
|
||||
|
||||
> Full developer documentation lives in this repo's **wiki** (sidebar link).
|
||||
>
|
||||
> See in particular: [Skin Creation Workflow](https://git.klud.top/danchie/tekton/wiki/Skin-Creation-Workflow), [Nakama Deployment](https://git.klud.top/danchie/tekton/wiki/Nakama-Deployment), and [Patch Release Workflow](https://git.klud.top/danchie/tekton/wiki/Patch-Release-Workflow).
|
||||
|
||||
## 🛠️ Developer Workflows
|
||||
## SSH setup for cloning
|
||||
|
||||
### Creating a Skin Material
|
||||
To create dynamic, color-maskable 3D materials for new character skins:
|
||||
- Open the **Skin Shader Generator** tool in the editor: `res://scenes/tools/skin_shader_generator.tscn`
|
||||
- Run the scene.
|
||||
- Import your base albedo and mask textures.
|
||||
- Use the UI to visualize UV overlays and adjust color channels (Red, Green, Blue, Alpha masks).
|
||||
- Export the configured material as a `.tres` file into the `assets/materials/skins/` directory.
|
||||
All clones **must use SSH** over Tailscale. HTTPS is disabled on this instance.
|
||||
|
||||
### Adding a Skin to the Shop
|
||||
Once your material is ready, you need to update the game's catalog and deploy the changes to the Nakama server.
|
||||
Guides by operating system:
|
||||
|
||||
#### Using the Catalog Editor Tool
|
||||
- Open the **Skin Catalog Editor** tool in the Godot Editor: `res://scenes/tools/skin_catalog_editor.tscn`
|
||||
- Press **F6** (or Right-click -> Run Current Scene).
|
||||
- **Manage Skins:**
|
||||
- Click **"+ New Skin"** to create a new entry.
|
||||
- Fill in the **ID**, **Name**, **Category**, and **Price** (Gold/Stars).
|
||||
- Assign the `.tres` material path generated in Step 1.
|
||||
- Click **"💾 Save & Generate"**. This automatically rewrites:
|
||||
- `res://scripts/managers/skin_manager.gd` (Local catalog)
|
||||
- `res://server/nakama/tekton_admin.js` (Server-side shop logic)
|
||||
- [Linux](https://git.klud.top/danchie/tekton/wiki/SSH-Setup-Linux)
|
||||
- [macOS](https://git.klud.top/danchie/tekton/wiki/SSH-Setup-macOS)
|
||||
- [Windows](https://git.klud.top/danchie/tekton/wiki/SSH-Setup-Windows)
|
||||
|
||||
#### Nakama VPS Deployment
|
||||
After generating the updated `tekton_admin.js` locally, you must sync it with your remote server.
|
||||
|
||||
- **Copy the latest script:** Open `server/nakama/tekton_admin.js` locally and copy its updated contents (including your new skin).
|
||||
- **Connect to your VPS** via SSH.
|
||||
- **Create/Edit the file on the remote server:**
|
||||
```bash
|
||||
nano ~/tekton_admin.js
|
||||
# Or use micro (recommended): micro ~/tekton_admin.js
|
||||
```
|
||||
Paste the copied contents and save the file.
|
||||
- **Find your Nakama Container ID:**
|
||||
It is highly recommended to use **lazydocker** to manage containers.
|
||||
*(To install on Ubuntu: `curl https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash`)*
|
||||
Open lazydocker or run `docker ps` to find the Container ID for your Nakama server.
|
||||
- **Copy the file into the Nakama container:**
|
||||
```bash
|
||||
# Replace ed21ac5d442a with your actual Container ID
|
||||
docker cp ~/tekton_admin.js ed21ac5d442a:/nakama/data/modules/tekton_admin.js
|
||||
```
|
||||
- **Restart the container** (via lazydocker or `docker restart <Container ID>`) for Nakama to load the new modules. Live game clients will fetch this new catalog automatically upon booting.
|
||||
|
||||
#### 🎨 Skin Creation & Deployment Flow
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% Creation Phase
|
||||
subgraph phase1 [Skin Material Creation]
|
||||
A[Albedo & Mask Textures] --> B{Skin Shader Generator}
|
||||
B -->|Export| C[material.tres]
|
||||
end
|
||||
|
||||
%% Catalog Phase
|
||||
subgraph phase2 [Catalog Definition]
|
||||
C --> D{Skin Catalog Editor}
|
||||
D -->|Save & Generate| E[tekton_admin.js]
|
||||
D -->|Save & Generate| F[skin_manager.gd]
|
||||
end
|
||||
|
||||
%% Deployment Phase (Dual Path)
|
||||
subgraph phase3 ["Shop Backend (VPS)"]
|
||||
E -->|SSH & nano| G[VPS: ~/tekton_admin.js]
|
||||
G -->|docker cp| H[Nakama Container]
|
||||
H -->|Restart| I[Live Shop Logic Sync]
|
||||
end
|
||||
|
||||
subgraph phase4 ["Asset Delivery (CI/CD)"]
|
||||
C --> J[Git Push]
|
||||
F --> J
|
||||
J -->|GitHub Actions| K[patch.pck]
|
||||
K -->|Automatic Download| L[Player Client Assets Sync]
|
||||
end
|
||||
Quick verification after setup:
|
||||
```bash
|
||||
ssh -T git@thunderobot -p 222
|
||||
```
|
||||
|
||||
### Pushing a New Version (Automated Patching)
|
||||
When you're ready to deploy new features or assets to players:
|
||||
- Document your changes in `CHANGELOG_DRAFT.md` using player-friendly language.
|
||||
- Run the version generation script from the terminal:
|
||||
```bash
|
||||
python generate_version_json.py --bump patch
|
||||
```
|
||||
*(Use `--bump minor` or `--bump major` for larger updates.)*
|
||||
- Commit and push your changes to the `main` branch on GitHub:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Release version X.Y.Z"
|
||||
git push origin main
|
||||
```
|
||||
- The **GitHub Actions Workflow** (`deploy_patch.yml`) will automatically detect the push, build the patch manifest (`version.json`), and deploy it to the public `gh-pages` branch.
|
||||
- Live game clients will detect the new version on boot, download the updated files, and apply the patch seamlessly.
|
||||
|
||||
### Local Testing & Understanding the Patch System
|
||||
When a player (or you) downloads an in-game patch, Godot downloads a `patch.pck` file to the system's `user://` directory.
|
||||
- **Virtual File System:** Godot mounts this `.pck` file over the `res://` directory purely in memory. **It does not physically overwrite your local source files** (like `assets/data/version.json`).
|
||||
- **Editor Bypass:** When testing locally in the Godot Editor, the `BootScreen` is configured to skip the remote network download and instead automatically parse your *local* `assets/data/version.json`.
|
||||
- **Previewing Changelogs:** To preview how your changelog will look before pushing to GitHub:
|
||||
- Add your notes under the `## [NEXT]` section in `CHANGELOG_DRAFT.md`.
|
||||
- Run `py tools/generate_version_json.py` from the terminal.
|
||||
- Run the `BootScreen` scene in the Godot Editor. It will instantly display the updated local UI!
|
||||
- **Syncing:** After the GitHub Actions CI builds a release online, remember to run `git pull origin main` to sync your local project files with the CI-generated files.
|
||||
|
||||
#### 🗺️ Architecture Flowchart
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% Local Dev Flow
|
||||
subgraph Local Dev Environment
|
||||
A[📝 CHANGELOG_DRAFT.md] -->|py tools/generate_version_json.py| B[(📄 version.json)]
|
||||
B -.->|Test in Editor| C{BootScreen}
|
||||
C -- Editor Bypass --> D[Reads Local version.json directly]
|
||||
end
|
||||
|
||||
%% CI Pipeline
|
||||
subgraph "CI/CD Pipeline"
|
||||
B -->|git push| E[⚡ GitHub Actions]
|
||||
E -->|Compiles & Builds| F[📦 patch.pck]
|
||||
F -->|Deploys| G((🌍 Public Repository))
|
||||
end
|
||||
|
||||
%% Live Client Flow
|
||||
subgraph Player Client
|
||||
G -.->|HTTP Download on Boot| H[📂 user://patch.pck]
|
||||
H -->|ProjectSettings.load_resource_pack| I[🧠 Godot Virtual File System]
|
||||
I -.->|Overrides res:// in Memory| J[Game Starts Updated!]
|
||||
end
|
||||
Once verified, clone:
|
||||
```bash
|
||||
git clone git@thunderobot:222/danchie/tekton.git
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Ongoing Features (Incoming)
|
||||
|
||||
### 🎰 Gacha System Backend Editor
|
||||
Currently in development: A dedicated backend editor tool (similar to `skin_catalog_editor.tscn`) specifically for managing the Gacha System.
|
||||
- **Nakama Syncing:** Will allow developers to push updated gacha pools, rates, and fragment costs directly to Nakama Storage.
|
||||
- **Dynamic Banners:** Will support updating specific slots on the gacha banner dynamically.
|
||||
- **Seasonal Rotations:** Will introduce automated scheduling so banners rotate based on active seasons and automatically remove themselves when the season ends.
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
@rpc("any_peer", "call_local")
|
||||
func remove_slow_effect():
|
||||
slow_timer = 0.0
|
||||
self.is_slowed = false
|
||||
if movement_manager:
|
||||
movement_manager.set_speed_multiplier(1.0)
|
||||
@@ -1,6 +0,0 @@
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func sync_clear_sticky_cell(pos: Vector2i) -> void:
|
||||
sticky_cells.erase(pos)
|
||||
mark_cleansed(pos)
|
||||
if gridmap:
|
||||
gridmap.set_cell_item(Vector3i(pos.x, 2, pos.y), -1)
|
||||
@@ -1,68 +0,0 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="FontFile" uid="uid://xnjx058n4tsw" path="res://assets/fonts/Nougat-ExtraBlack.ttf" id="1_font"]
|
||||
|
||||
[node name="GauntletHUD" type="CanvasLayer"]
|
||||
layer = 5
|
||||
visible = false
|
||||
|
||||
[node name="TopContainer" type="CenterContainer" parent="."]
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_top = 70.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="SlowMoLabel" type="Label" parent="TopContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 18
|
||||
theme_override_colors/font_color = Color(0.3, 0.5, 1.0, 1)
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 4
|
||||
theme_override_fonts/font = ExtResource("1_font")
|
||||
text = "SLOW-MO"
|
||||
horizontal_alignment = 1
|
||||
visible = false
|
||||
|
||||
[node name="BottomContainer" type="CenterContainer" parent="."]
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -120.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="BottomContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="PhaseLabel" type="Label" parent="BottomContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 24
|
||||
theme_override_colors/font_color = Color(1, 0.6, 0.8, 1)
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 6
|
||||
theme_override_fonts/font = ExtResource("1_font")
|
||||
text = "🍬 OPEN ARENA"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CleanserHBox" type="HBoxContainer" parent="BottomContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 6
|
||||
alignment = 1
|
||||
|
||||
[node name="CleanserIcon" type="TextureRect" parent="BottomContainer/VBoxContainer/CleanserHBox"]
|
||||
layout_mode = 2
|
||||
custom_minimum_size = Vector2(20, 20)
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="CleanserLabel" type="Label" parent="BottomContainer/VBoxContainer/CleanserHBox"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 6
|
||||
theme_override_fonts/font = ExtResource("1_font")
|
||||
text = "[E] Cleanser (0)"
|
||||
horizontal_alignment = 1
|
||||
@@ -1,48 +0,0 @@
|
||||
func _spawn_cleanser_particles(pos: Vector2i) -> void:
|
||||
"""Spawn bright cleansing particles when sticky is cleared."""
|
||||
if not main_scene or not gridmap:
|
||||
return
|
||||
|
||||
var world_pos = Vector3(
|
||||
pos.x * gridmap.cell_size.x + gridmap.cell_size.x / 2.0,
|
||||
0.5,
|
||||
pos.y * gridmap.cell_size.z + gridmap.cell_size.z / 2.0
|
||||
)
|
||||
|
||||
var particles = GPUParticles3D.new()
|
||||
particles.emitting = true
|
||||
particles.one_shot = true
|
||||
particles.amount = 12
|
||||
particles.lifetime = 0.6
|
||||
particles.explosiveness = 0.9
|
||||
|
||||
var material = ParticleProcessMaterial.new()
|
||||
material.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_SPHERE
|
||||
material.emission_sphere_radius = 0.3
|
||||
material.direction = Vector3(0, 1, 0)
|
||||
material.spread = 180.0
|
||||
material.initial_velocity_min = 3.0
|
||||
material.initial_velocity_max = 5.0
|
||||
material.gravity = Vector3(0, -5.0, 0)
|
||||
material.scale_min = 0.05
|
||||
material.scale_max = 0.15
|
||||
|
||||
var mesh = SphereMesh.new()
|
||||
mesh.radius = 0.2
|
||||
mesh.height = 0.4
|
||||
var spatial_mat = StandardMaterial3D.new()
|
||||
spatial_mat.albedo_color = Color(0.2, 1.0, 1.0) # Cyan/Blue for cleanser
|
||||
spatial_mat.emission_enabled = true
|
||||
spatial_mat.emission = Color(0.2, 1.0, 1.0)
|
||||
spatial_mat.emission_energy_multiplier = 3.0
|
||||
mesh.material = spatial_mat
|
||||
particles.draw_pass_1 = mesh
|
||||
|
||||
particles.process_material = material
|
||||
particles.position = world_pos
|
||||
|
||||
main_scene.add_child(particles)
|
||||
|
||||
await get_tree().create_timer(1.2).timeout
|
||||
if particles and is_instance_valid(particles):
|
||||
particles.queue_free()
|
||||
@@ -1,24 +0,0 @@
|
||||
func _find_valid_drop_position() -> Vector2i:
|
||||
# Try random adjacent cells
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
neighbors.shuffle()
|
||||
|
||||
for neighbor in neighbors:
|
||||
var pos = neighbor.position
|
||||
# Check item layer
|
||||
var item_cell = Vector3i(pos.x, 1, pos.y)
|
||||
if enhanced_gridmap.get_cell_item(item_cell) == -1:
|
||||
if not is_position_occupied(pos):
|
||||
# Gauntlet Mode explicit overrides
|
||||
var gm = null
|
||||
var main_gauntlet = get_tree().root.get_node_or_null("Main")
|
||||
if main_gauntlet and main_gauntlet.get("gauntlet_manager"):
|
||||
gm = main_gauntlet.gauntlet_manager
|
||||
if gm and gm.is_active:
|
||||
if pos.x == 0 or pos.x == gm.ARENA_COLUMNS - 1 or pos.y == 0 or pos.y == gm.ARENA_ROWS - 1:
|
||||
continue
|
||||
if gm._is_npc_zone(pos):
|
||||
continue
|
||||
return pos
|
||||
|
||||
return Vector2i(-1, -1)
|
||||
@@ -1,8 +0,0 @@
|
||||
@rpc("any_peer", "call_local")
|
||||
func remove_slow_effect():
|
||||
slow_timer = 0.0
|
||||
self.is_slowed = false
|
||||
if movement_manager:
|
||||
# INSTANT response: restore speed multiplier to 1.0 immediately
|
||||
movement_manager.set_speed_multiplier(1.0)
|
||||
print("Player %s slow effect removed early" % name)
|
||||
@@ -1,25 +0,0 @@
|
||||
/func _find_valid_drop_position/,/return Vector2i(-1, -1)/c\
|
||||
func _find_valid_drop_position() -> Vector2i:\
|
||||
# Try random adjacent cells\
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)\
|
||||
neighbors.shuffle()\
|
||||
\
|
||||
for neighbor in neighbors:\
|
||||
var pos = neighbor.position\
|
||||
# Check item layer\
|
||||
var item_cell = Vector3i(pos.x, 1, pos.y)\
|
||||
if enhanced_gridmap.get_cell_item(item_cell) == -1:\
|
||||
if not is_position_occupied(pos):\
|
||||
# Gauntlet Mode explicit overrides\
|
||||
var gm = null\
|
||||
var main_gauntlet = get_tree().root.get_node_or_null("Main")\
|
||||
if main_gauntlet and main_gauntlet.get("gauntlet_manager"):\
|
||||
gm = main_gauntlet.gauntlet_manager\
|
||||
if gm and gm.is_active:\
|
||||
if pos.x == 0 or pos.x == gm.ARENA_COLUMNS - 1 or pos.y == 0 or pos.y == gm.ARENA_ROWS - 1:\
|
||||
continue\
|
||||
if gm._is_npc_zone(pos):\
|
||||
continue\
|
||||
return pos\
|
||||
\
|
||||
return Vector2i(-1, -1)
|
||||
@@ -128,8 +128,10 @@ func spawn_projectile(target_world_pos: Vector3, duration: float) -> void:
|
||||
# We need to wait for the X/Z tween to finish, but since it's parallel we can just use a separate timer or tween
|
||||
# to kill the projectile exactly when duration is reached, ensuring it doesn't get killed early by X/Z finishing 1 frame earlier than Y
|
||||
get_tree().create_timer(duration).timeout.connect(func():
|
||||
if is_instance_valid(spin_tween): spin_tween.kill()
|
||||
if is_instance_valid(projectile): projectile.queue_free()
|
||||
if is_instance_valid(spin_tween):
|
||||
spin_tween.kill()
|
||||
if is_instance_valid(projectile):
|
||||
projectile.queue_free()
|
||||
)
|
||||
|
||||
func can_rpc() -> bool:
|
||||
|
||||
@@ -391,47 +391,45 @@ func sync_arena_setup() -> void:
|
||||
print("[Gauntlet] Client: Syncing Arena Setup (%dx%d)..." % [ARENA_COLUMNS, ARENA_ROWS])
|
||||
_apply_arena_setup()
|
||||
|
||||
func _apply_arena_setup() -> void:
|
||||
"""Shared arena layout logic for host + clients."""
|
||||
if not gridmap:
|
||||
gridmap = get_parent().get_node_or_null("EnhancedGridMap")
|
||||
if not gridmap:
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if not gridmap: return
|
||||
|
||||
# Resize grid (bypass setters that wipe the map)
|
||||
gridmap.set("columns", ARENA_COLUMNS)
|
||||
gridmap.set("rows", ARENA_ROWS)
|
||||
|
||||
# Clear all
|
||||
gridmap.clear()
|
||||
|
||||
# Build the 20x20 arena
|
||||
for x in range(ARENA_COLUMNS):
|
||||
for z in range(ARENA_ROWS):
|
||||
var pos = Vector2i(x, z)
|
||||
|
||||
# Center 3x3 block: NPC obstacle (Candy Pump)
|
||||
if _is_npc_zone(pos):
|
||||
# Make the floor empty (-1) beneath the Candy Pump
|
||||
# We need to clear all possible layers just in case
|
||||
gridmap.set_cell_item(Vector3i(x, 0, z), -1)
|
||||
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
|
||||
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
|
||||
continue
|
||||
|
||||
# Boundary walls: perimeter (row 0, row 19, col 0, col 19)
|
||||
if x == 0 or x == ARENA_COLUMNS - 1 or z == 0 or z == ARENA_ROWS - 1:
|
||||
# Also make border walls visually walkable floors instead of red blocks
|
||||
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
|
||||
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
|
||||
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
|
||||
continue
|
||||
|
||||
# Interior: walkable floor
|
||||
func _apply_arena_setup() -> void:
|
||||
"""Shared arena layout logic for host + clients."""
|
||||
if not gridmap:
|
||||
gridmap = get_parent().get_node_or_null("EnhancedGridMap")
|
||||
if not gridmap:
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if not gridmap: return
|
||||
|
||||
# Resize grid (bypass setters that wipe the map)
|
||||
gridmap.set("columns", ARENA_COLUMNS)
|
||||
gridmap.set("rows", ARENA_ROWS)
|
||||
|
||||
# Clear all
|
||||
gridmap.clear()
|
||||
|
||||
# Build the 20x20 arena
|
||||
for x in range(ARENA_COLUMNS):
|
||||
for z in range(ARENA_ROWS):
|
||||
var pos = Vector2i(x, z)
|
||||
|
||||
# Center 3x3 block: NPC obstacle (Candy Pump)
|
||||
if x >= 8 and x <= 10 and z >= 8 and z <= 10:
|
||||
# Hardcode clear all possible layers beneath the Candy Pump
|
||||
for layer in range(5):
|
||||
gridmap.set_cell_item(Vector3i(x, layer, z), -1)
|
||||
continue
|
||||
|
||||
# Boundary walls: perimeter (row 0, row 19, col 0, col 19)
|
||||
if x == 0 or x == ARENA_COLUMNS - 1 or z == 0 or z == ARENA_ROWS - 1:
|
||||
# Also make border walls visually walkable floors instead of red blocks
|
||||
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
|
||||
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
|
||||
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
|
||||
continue
|
||||
|
||||
# Interior: walkable floor
|
||||
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
|
||||
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
|
||||
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
|
||||
|
||||
gridmap.diagonal_movement = true
|
||||
gridmap.update_grid_data()
|
||||
@@ -451,10 +449,7 @@ func sync_arena_setup() -> void:
|
||||
|
||||
func _is_npc_zone(pos: Vector2i) -> bool:
|
||||
"""Check if a position is within the center 3x3 NPC zone."""
|
||||
var half = NPC_SIZE / 2 # integer division = 1
|
||||
var min_coord = NPC_CENTER - Vector2i(half, half) # (8, 8)
|
||||
var max_coord = NPC_CENTER + Vector2i(half, half) # (10, 10)
|
||||
return pos.x >= min_coord.x and pos.x <= max_coord.x and pos.y >= min_coord.y and pos.y <= max_coord.y
|
||||
return pos.x >= 8 and pos.x <= 10 and pos.y >= 8 and pos.y <= 10
|
||||
|
||||
func get_spawn_points(player_count: int) -> Array[Vector2i]:
|
||||
"""Return spawn positions based on player count. Inside boundary walls."""
|
||||
@@ -508,13 +503,14 @@ func _spawn_mission_tiles() -> void:
|
||||
# Goal items: Heart(7), Diamond(8), Star(9), Coin(10)
|
||||
var goal_items = [7, 8, 9, 10]
|
||||
var tiles_spawned: int = 0
|
||||
var main = get_node_or_null("/root/Main")
|
||||
|
||||
for x in range(ARENA_COLUMNS):
|
||||
for z in range(ARENA_ROWS):
|
||||
var pos = Vector2i(x, z)
|
||||
|
||||
# Skip NPC pump zone (center 3x3)
|
||||
if _is_npc_zone(pos):
|
||||
if x >= 8 and x <= 10 and z >= 8 and z <= 10:
|
||||
continue
|
||||
|
||||
# Check base floor — don't spawn on void (or walls if they were still obstacles)
|
||||
@@ -540,7 +536,6 @@ func _spawn_mission_tiles() -> void:
|
||||
tiles_spawned += 1
|
||||
|
||||
# Sync to clients
|
||||
var main = get_node("/root/Main")
|
||||
if main:
|
||||
main.rpc("sync_grid_item", x, 1, z, tile_type)
|
||||
|
||||
@@ -858,6 +853,8 @@ func sync_growth_telegraph(cells: Array) -> void:
|
||||
|
||||
for cell in cells:
|
||||
var pos = cell as Vector2i
|
||||
if pos.x >= 8 and pos.x <= 10 and pos.y >= 8 and pos.y <= 10: continue
|
||||
|
||||
# Telegraph overlay tile on Layer 2 (still passable).
|
||||
gridmap.set_cell_item(Vector3i(pos.x, 2, pos.y), TILE_TELEGRAPH)
|
||||
_spawn_telegraph_highlight(pos)
|
||||
@@ -929,6 +926,8 @@ func sync_growth_apply(cells: Array) -> void:
|
||||
if not gridmap: return
|
||||
for cell in cells:
|
||||
var pos = cell as Vector2i
|
||||
if pos.x >= 8 and pos.x <= 10 and pos.y >= 8 and pos.y <= 10: continue
|
||||
|
||||
gridmap.set_cell_item(Vector3i(pos.x, 2, pos.y), TILE_STICKY)
|
||||
sticky_cells[pos] = true
|
||||
|
||||
@@ -1518,6 +1517,8 @@ func sync_bubble_spawn(center: Vector2i, cells: Array) -> void:
|
||||
# Telegraph-style warning overlay on the footprint (still passable).
|
||||
for c in cells:
|
||||
var pos = c as Vector2i
|
||||
if pos.x >= 8 and pos.x <= 10 and pos.y >= 8 and pos.y <= 10: continue
|
||||
|
||||
gridmap.set_cell_item(Vector3i(pos.x, 2, pos.y), TILE_TELEGRAPH)
|
||||
_spawn_bubble_visual(center)
|
||||
if SfxManager:
|
||||
@@ -1539,6 +1540,8 @@ func sync_bubble_explode(center: Vector2i, cells: Array) -> void:
|
||||
return
|
||||
for c in cells:
|
||||
var pos = c as Vector2i
|
||||
if pos.x >= 8 and pos.x <= 10 and pos.y >= 8 and pos.y <= 10: continue
|
||||
|
||||
gridmap.set_cell_item(Vector3i(pos.x, 2, pos.y), TILE_STICKY)
|
||||
sticky_cells[pos] = true
|
||||
# Medium shake — bubbles hit harder than a normal growth tick.
|
||||
|
||||
Reference in New Issue
Block a user