9 Commits

Author SHA1 Message Date
3a3a83b071 update readme
Some checks failed
CI / Tests (push) Failing after 47s
CI / Clippy lints (push) Failing after 52s
CI / Bevy lints (push) Failing after 1m21s
2026-03-18 15:35:12 -04:00
69215bdb91 update workflow
Some checks failed
CI / Tests (push) Failing after 1m10s
CI / Clippy lints (push) Failing after 1m24s
CI / Bevy lints (push) Failing after 1m50s
2026-03-18 15:24:56 -04:00
9f8d1888ec update workflow 2026-03-18 15:21:38 -04:00
ebae1599f1 building spawning update
Some checks failed
Rust / build (push) Failing after 4s
2026-03-18 15:15:11 -04:00
8bf58bb04c more ui testing
Some checks failed
Rust / build (push) Failing after 4s
2026-03-17 17:57:41 -04:00
f342970228 ui testing
Some checks failed
Rust / build (push) Failing after 4s
2026-03-16 22:58:12 -04:00
fca907aee4 ui testing
Some checks failed
Rust / build (push) Failing after 4s
2026-03-16 20:31:40 -04:00
f9e96cc74b configured ui camera
Some checks failed
Rust / build (push) Failing after 4s
2026-03-16 16:59:40 -04:00
3551ecfde8 configured ui camera 2026-03-16 16:59:29 -04:00
20 changed files with 1215 additions and 182 deletions

140
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,140 @@
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
env:
# Reduce compile time and cache size.
RUSTFLAGS: -Zshare-generics=y -Zthreads=0
RUSTDOCFLAGS: -Zshare-generics=y -Zthreads=0
# Use the same Rust toolchain across jobs so they can share a cache.
toolchain: nightly-2025-04-03
jobs:
# Run Clippy lints.
clippy-lints:
name: Clippy lints
runs-on: ubuntu-latest
env:
RUSTFLAGS: "-Dwarnings"
timeout-minutes: 20
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.toolchain }}
components: clippy
- name: Restore Rust cache
id: cache
uses: Swatinem/rust-cache@v2
with:
shared-key: ci
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install build dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: sudo apt-get -y update; sudo apt-get -y install --no-install-recommends libasound2-dev libudev-dev libwayland-dev
- name: Run Clippy lints
run: cargo clippy --locked --workspace --all-targets --profile ci --all-features
# Run Bevy lints.
bevy-lints:
name: Bevy lints
runs-on: ubuntu-latest
env:
RUSTFLAGS: "-Dwarnings"
timeout-minutes: 20
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain (plus bevy_lint)
uses: TheBevyFlock/bevy_cli/bevy_lint@lint-v0.3.0
- name: Restore Rust cache
id: cache
uses: Swatinem/rust-cache@v2
with:
shared-key: ci
save-if: false
- name: Install build dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: sudo apt-get -y update; sudo apt-get -y install --no-install-recommends libasound2-dev libudev-dev libwayland-dev
- name: Run Bevy lints
run: bevy_lint --locked --workspace --all-targets --profile ci --all-features
# Run tests.
tests:
name: Tests
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up environment
run: echo "RUSTFLAGS=${RUSTFLAGS:+$RUSTFLAGS }-Zcodegen-backend=cranelift" >> "${GITHUB_ENV}"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.toolchain }}
components: rustc-codegen-cranelift-preview
- name: Restore Rust cache
uses: Swatinem/rust-cache@v2
with:
shared-key: test
cache-directories: ${{ env.LD_LIBRARY_PATH }}
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install build dependencies
run: sudo apt-get -y update; sudo apt-get -y install --no-install-recommends libasound2-dev libudev-dev libwayland-dev
- name: Run tests
run: cargo test --locked --workspace --all-targets --profile ci --no-fail-fast
# Check that the web build compiles.
# check-web:
# name: Check web
# runs-on: ubuntu-latest
# env:
# RUSTFLAGS: -Zshare-generics=y -Zthreads=0 --cfg getrandom_backend="wasm_js"
# timeout-minutes: 20
# steps:
# - name: Checkout repository
# uses: actions/checkout@v4
# - name: Install Rust toolchain
# uses: dtolnay/rust-toolchain@master
# with:
# toolchain: ${{ env.toolchain }}
# targets: wasm32-unknown-unknown
# - name: Restore Rust cache
# id: cache
# uses: Swatinem/rust-cache@v2
# with:
# shared-key: web-ci
# save-if: ${{ github.ref == 'refs/heads/main' }}
# - name: Install build dependencies
# if: steps.cache.outputs.cache-hit != 'true'
# run: sudo apt-get -y update; sudo apt-get -y install --no-install-recommends libasound2-dev libudev-dev libwayland-dev
# - name: Check web
# run: cargo check --config 'profile.web.inherits="dev"' --profile ci --no-default-features --features "dev web" --target wasm32-unknown-unknown

335
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,335 @@
name: Release
on:
# Trigger this workflow when a tag is pushed in the format `v1.2.3`.
push:
tags:
# Pattern syntax: <https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet>.
- "v[0-9]+.[0-9]+.[0-9]+*"
# Trigger this workflow manually via workflow dispatch.
workflow_dispatch:
inputs:
version:
description: "Version number in the format `v1.2.3`"
required: true
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
# Configure the release workflow by editing the following values.
env:
# The base filename of the binary produced by `cargo build`.
cargo_build_binary_name: phos
# The path to the assets directory.
assets_path: assets
# Whether to build and package a release for a given target platform.
build_for_web: false
build_for_linux: true
build_for_windows: true
build_for_macos: false
# Whether to upload the packages produced by this workflow to a GitHub release.
upload_to_github: true
# The itch.io project to upload to in the format `user-name/project-name`.
# There will be no upload to itch.io if this is commented out.
# upload_to_itch: amatsugu/phos
############
# ADVANCED #
############
# The ID of the app produced by this workflow.
# Applies to macOS releases.
# Must contain only A-Z, a-z, 0-9, hyphen, and period: <https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleidentifier>.
app_id: amatsugu.phos
# The base filename of the binary in the package produced by this workflow.
# Applies to Windows, macOS, and Linux releases.
# Defaults to `cargo_build_binary_name` if commented out.
#app_binary_name: bevy_jam_6
# The name of the `.zip` or `.dmg` file produced by this workflow.
# Defaults to `app_binary_name` if commented out.
#app_package_name: bevy-new-2d
# The display name of the app produced by this workflow.
# Applies to macOS releases.
# Defaults to `app_package_name` if commented out.
app_display_name: phos
# The short display name of the app produced by this workflow.
# Applies to macOS releases.
# Must be 15 or fewer characters: <https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundlename>.
# Defaults to `app_display_name` if commented out.
#app_short_name: Phos
# Before enabling LFS, please take a look at GitHub's documentation for costs and quota limits:
# <https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-storage-and-bandwidth-usage>
git_lfs: false
# Enabling this only helps with consecutive releases to the same tag (and takes up cache storage space).
# See: <https://github.com/orgs/community/discussions/27059>.
use_github_cache: false
# Reduce compile time.
RUSTFLAGS: -Zshare-generics=y -Zthreads=0
jobs:
# Forward some environment variables as outputs of this job.
# This is needed because the `env` context can't be used in the `if:` condition of a job:
# <https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability>
forward-env:
runs-on: ubuntu-latest
steps:
- name: Do nothing
run: "true"
outputs:
upload_to_itch: ${{ env.upload_to_itch }}
# Determine the version number for this workflow.
get-version:
runs-on: ubuntu-latest
steps:
- name: Determine version number
id: tag
run: echo "tag=${GITHUB_REF#refs/tags/}" >> "${GITHUB_OUTPUT}"
outputs:
# Use the input from workflow dispatch, or fall back to the git tag.
version: ${{ inputs.version || steps.tag.outputs.tag }}
# Build and package a release for each platform.
build:
needs:
- get-version
env:
version: ${{ needs.get-version.outputs.version }}
# Avoid rate-limiting. See: <https://github.com/cargo-bins/cargo-binstall/issues/2045>.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
matrix:
include:
- platform: web
targets: wasm32-unknown-unknown
package_ext: .zip
runner: ubuntu-latest
- platform: linux
targets: x86_64-unknown-linux-gnu
package_ext: .zip
runner: ubuntu-latest
- platform: windows
targets: x86_64-pc-windows-msvc
binary_ext: .exe
package_ext: .zip
runner: windows-latest
- platform: macos
targets: x86_64-apple-darwin aarch64-apple-darwin
app_suffix: .app/Contents/MacOS
package_ext: .dmg
runner: macos-latest
runs-on: ${{ matrix.runner }}
permissions:
# Required to create a GitHub release: <https://docs.github.com/en/rest/releases/releases#create-a-release>.
contents: write
defaults:
run:
shell: bash
steps:
- name: Set up environment
run: |
# Default values:
echo "app_binary_name=${app_binary_name:=${{ env.cargo_build_binary_name }}}" >> "${GITHUB_ENV}"
echo "app_package_name=${app_package_name:=${app_binary_name}}" >> "${GITHUB_ENV}"
echo "app_display_name=${app_display_name:=${app_package_name}}" >> "${GITHUB_ENV}"
echo "app_short_name=${app_short_name:=${app_display_name}}" >> "${GITHUB_ENV}"
# File paths:
echo "app=tmp/app/${app_package_name}"'${{ matrix.app_suffix }}' >> "${GITHUB_ENV}"
echo "package=${app_package_name}-"'${{ matrix.platform }}${{ matrix.package_ext }}' >> "${GITHUB_ENV}"
# macOS environment:
if [ '${{ matrix.platform }}' = 'macos' ]; then
echo 'MACOSX_DEPLOYMENT_TARGET=11.0' >> "${GITHUB_ENV}" # macOS 11.0 Big Sur is the first version to support universal binaries.
echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> "${GITHUB_ENV}"
fi
# Check if building for this platform is enabled.
echo 'is_platform_enabled=${{
(matrix.platform == 'web' && env.build_for_web == 'true') ||
(matrix.platform == 'linux' && env.build_for_linux == 'true') ||
(matrix.platform == 'windows' && env.build_for_windows == 'true') ||
(matrix.platform == 'macos' && env.build_for_macos == 'true')
}}' >> "${GITHUB_ENV}"
- name: Checkout repository
if: ${{ env.is_platform_enabled == 'true' }}
uses: actions/checkout@v4
with:
lfs: ${{ env.git_lfs }}
- name: Install Rust toolchain
if: ${{ env.is_platform_enabled == 'true' }}
uses: dtolnay/rust-toolchain@nightly
with:
targets: ${{ matrix.targets }}
- name: Restore Rust cache
if: ${{ env.is_platform_enabled == 'true' && env.use_github_cache == 'true' }}
uses: Swatinem/rust-cache@v2
with:
shared-key: release
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install build dependencies (Linux)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'linux' }}
run: sudo apt-get -y update; sudo apt-get -y install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev
- name: Prepare output directories
if: ${{ env.is_platform_enabled == 'true' }}
run: rm -rf tmp; mkdir -p tmp/binary '${{ env.app }}'
- name: Install cargo-binstall
if: ${{ env.is_platform_enabled == 'true' }}
uses: cargo-bins/cargo-binstall@main
- name: Install Bevy CLI
if: ${{ env.is_platform_enabled == 'true' }}
run: cargo binstall --locked --no-confirm --force --git='https://github.com/TheBevyFlock/bevy_cli' bevy_cli
- name: Build and add web bundle to app (Web)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'web' }}
run: |
cargo binstall --locked --no-confirm --force wasm-bindgen-cli
cargo binstall --locked --no-confirm --force wasm-opt
RUSTFLAGS='-Zshare-generics=y -Zthreads=0 --cfg getrandom_backend="wasm_js"' bevy build --locked --release --features='${{ matrix.features }} web' --yes web --bundle
mv 'target/bevy_web/web-release/${{ env.cargo_build_binary_name }}' '${{ env.app }}'
- name: Build and add binaries to app (non-Web)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform != 'web' }}
run: |
for target in ${{ matrix.targets }}; do
bevy build --locked --release --target="${target}" --features='${{ matrix.features }}'
mv target/"${target}"/release/'${{ env.cargo_build_binary_name }}${{ matrix.binary_ext }}' tmp/binary/"${target}"'${{ matrix.binary_ext }}'
done
if [ '${{ matrix.platform }}' = 'macos' ]; then
lipo tmp/binary/*'${{ matrix.binary_ext }}' -create -output '${{ env.app }}/${{ env.app_binary_name }}${{ matrix.binary_ext }}'
else
mv tmp/binary/*'${{ matrix.binary_ext }}' '${{ env.app }}/${{ env.app_binary_name }}${{ matrix.binary_ext }}'
fi
- name: Add assets to app (non-Web)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform != 'web' }}
run: cp -R ./'${{ env.assets_path }}' '${{ env.app }}' || true # Ignore error if assets folder does not exist.
- name: Add metadata to app (macOS)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'macos' }}
run: |
cat >'${{ env.app }}/../Info.plist' <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${{ env.app_display_name }}</string>
<key>CFBundleExecutable</key>
<string>${{ env.app_binary_name }}</string>
<key>CFBundleIdentifier</key>
<string>${{ env.app_id }}</string>
<key>CFBundleName</key>
<string>${{ env.app_short_name }}</string>
<key>CFBundleShortVersionString</key>
<string>${{ env.version }}</string>
<key>CFBundleVersion</key>
<string>${{ env.version }}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>
EOF
- name: Package app (non-Windows)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform != 'windows' }}
working-directory: tmp/app
run: |
if [ '${{ matrix.platform }}' = 'macos' ]; then
ln -s /Applications .
hdiutil create -fs HFS+ -volname '${{ env.app_package_name }}' -srcfolder . '${{ env.package }}'
else
zip --recurse-paths '${{ env.package }}' '${{ env.app_package_name }}'
fi
- name: Package app (Windows)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'windows' }}
working-directory: tmp/app
shell: pwsh
run: Compress-Archive -Path '${{ env.app_package_name }}' -DestinationPath '${{ env.package }}'
- name: Upload package to workflow artifacts
if: ${{ env.is_platform_enabled == 'true' }}
uses: actions/upload-artifact@v4
with:
path: tmp/app/${{ env.package }}
name: package-${{ matrix.platform }}
retention-days: 1
- name: Upload package to GitHub release
if: ${{ env.is_platform_enabled == 'true' && env.upload_to_github == 'true' }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: tmp/app/${{ env.package }}
asset_name: ${{ env.package }}
release_name: ${{ env.version }}
tag: ${{ env.version }}
overwrite: true
# Upload all packages to itch.io.
upload-to-itch:
runs-on: ubuntu-latest
needs:
- forward-env
- get-version
- build
if: ${{ needs.forward-env.outputs.upload_to_itch != '' }}
steps:
- name: Download all packages
uses: actions/download-artifact@v4
with:
pattern: package-*
path: tmp
- name: Install butler
run: |
curl -L -o butler.zip 'https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default'
unzip butler.zip
chmod +x butler
./butler -V
- name: Upload all packages to itch.io
env:
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
run: |
for channel in $(ls tmp); do
./butler push \
--fix-permissions \
--userversion='${{ needs.get-version.outputs.version }}' \
tmp/"${channel}"/* \
'${{ env.upload_to_itch }}':"${channel#package-}"
done

347
.github/workflows/release.yaml.template vendored Normal file
View File

@@ -0,0 +1,347 @@
name: Release
on:
# Trigger this workflow when a tag is pushed in the format `v1.2.3`.
push:
tags:
# Pattern syntax: <https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet>.
- "v[0-9]+.[0-9]+.[0-9]+*"
# Trigger this workflow manually via workflow dispatch.
workflow_dispatch:
inputs:
version:
description: "Version number in the format `v1.2.3`"
required: true
type: string
{% raw -%}
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
{%- endraw %}
# Configure the release workflow by editing the following values.
env:
# The base filename of the binary produced by `cargo build`.
cargo_build_binary_name: {{project-name}}
# The path to the assets directory.
assets_path: assets
# Whether to build and package a release for a given target platform.
build_for_web: true
build_for_linux: true
build_for_windows: true
build_for_macos: true
# Whether to upload the packages produced by this workflow to a GitHub release.
upload_to_github: true
# The itch.io project to upload to in the format `user-name/project-name`.
# There will be no upload to itch.io if this is commented out.
{%- if itch_username != "" %}
{%- if itch_project != "" %}
upload_to_itch: {{itch_username}}/{{itch_project}}
{%- else %}
upload_to_itch: {{itch_username}}/{{project-name}}
{%- endif %}
{%- else %}
#upload_to_itch: your-itch-username/{{project-name}}
{%- endif %}
############
# ADVANCED #
############
# The ID of the app produced by this workflow.
# Applies to macOS releases.
# Must contain only A-Z, a-z, 0-9, hyphen, and period: <https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleidentifier>.
app_id: {{itch_username | kebab_case}}.{{project-name | kebab_case}}
# The base filename of the binary in the package produced by this workflow.
# Applies to Windows, macOS, and Linux releases.
# Defaults to `cargo_build_binary_name` if commented out.
#app_binary_name: {{project-name}}
# The name of the `.zip` or `.dmg` file produced by this workflow.
# Defaults to `app_binary_name` if commented out.
#app_package_name: {{project-name | kebab_case}}
# The display name of the app produced by this workflow.
# Applies to macOS releases.
# Defaults to `app_package_name` if commented out.
#app_display_name: {{project-name | title_case}}
# The short display name of the app produced by this workflow.
# Applies to macOS releases.
# Must be 15 or fewer characters: <https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundlename>.
# Defaults to `app_display_name` if commented out.
#app_short_name: {{project-name | title_case | truncate: 15, "…"}}
# Before enabling LFS, please take a look at GitHub's documentation for costs and quota limits:
# <https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-storage-and-bandwidth-usage>
git_lfs: false
# Enabling this only helps with consecutive releases to the same tag (and takes up cache storage space).
# See: <https://github.com/orgs/community/discussions/27059>.
use_github_cache: false
# Reduce compile time.
RUSTFLAGS: -Dwarnings -Zshare-generics=y -Zthreads=0
{% raw -%}
jobs:
# Forward some environment variables as outputs of this job.
# This is needed because the `env` context can't be used in the `if:` condition of a job:
# <https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability>
forward-env:
runs-on: ubuntu-latest
steps:
- name: Do nothing
run: "true"
outputs:
upload_to_itch: ${{ env.upload_to_itch }}
# Determine the version number for this workflow.
get-version:
runs-on: ubuntu-latest
steps:
- name: Determine version number
id: tag
run: echo "tag=${GITHUB_REF#refs/tags/}" >> "${GITHUB_OUTPUT}"
outputs:
# Use the input from workflow dispatch, or fall back to the git tag.
version: ${{ inputs.version || steps.tag.outputs.tag }}
# Build and package a release for each platform.
build:
needs:
- get-version
env:
version: ${{ needs.get-version.outputs.version }}
# Avoid rate-limiting. See: <https://github.com/cargo-bins/cargo-binstall/issues/2045>.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
matrix:
include:
- platform: web
targets: wasm32-unknown-unknown
package_ext: .zip
runner: ubuntu-latest
- platform: linux
targets: x86_64-unknown-linux-gnu
package_ext: .zip
runner: ubuntu-latest
- platform: windows
targets: x86_64-pc-windows-msvc
binary_ext: .exe
package_ext: .zip
runner: windows-latest
- platform: macos
targets: x86_64-apple-darwin aarch64-apple-darwin
app_suffix: .app/Contents/MacOS
package_ext: .dmg
runner: macos-latest
runs-on: ${{ matrix.runner }}
permissions:
# Required to create a GitHub release: <https://docs.github.com/en/rest/releases/releases#create-a-release>.
contents: write
defaults:
run:
shell: bash
steps:
- name: Set up environment
run: |
# Default values:
echo "app_binary_name=${app_binary_name:=${{ env.cargo_build_binary_name }}}" >> "${GITHUB_ENV}"
echo "app_package_name=${app_package_name:=${app_binary_name}}" >> "${GITHUB_ENV}"
echo "app_display_name=${app_display_name:=${app_package_name}}" >> "${GITHUB_ENV}"
echo "app_short_name=${app_short_name:=${app_display_name}}" >> "${GITHUB_ENV}"
# File paths:
echo "app=tmp/app/${app_package_name}"'${{ matrix.app_suffix }}' >> "${GITHUB_ENV}"
echo "package=${app_package_name}-"'${{ matrix.platform }}${{ matrix.package_ext }}' >> "${GITHUB_ENV}"
# macOS environment:
if [ '${{ matrix.platform }}' = 'macos' ]; then
echo 'MACOSX_DEPLOYMENT_TARGET=11.0' >> "${GITHUB_ENV}" # macOS 11.0 Big Sur is the first version to support universal binaries.
echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> "${GITHUB_ENV}"
fi
# Check if building for this platform is enabled.
echo 'is_platform_enabled=${{
(matrix.platform == 'web' && env.build_for_web == 'true') ||
(matrix.platform == 'linux' && env.build_for_linux == 'true') ||
(matrix.platform == 'windows' && env.build_for_windows == 'true') ||
(matrix.platform == 'macos' && env.build_for_macos == 'true')
}}' >> "${GITHUB_ENV}"
- name: Checkout repository
if: ${{ env.is_platform_enabled == 'true' }}
uses: actions/checkout@v4
with:
lfs: ${{ env.git_lfs }}
- name: Install Rust toolchain
if: ${{ env.is_platform_enabled == 'true' }}
uses: dtolnay/rust-toolchain@nightly
with:
targets: ${{ matrix.targets }}
- name: Restore Rust cache
if: ${{ env.is_platform_enabled == 'true' && env.use_github_cache == 'true' }}
uses: Swatinem/rust-cache@v2
with:
shared-key: release
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install build dependencies (Linux)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'linux' }}
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev
- name: Prepare output directories
if: ${{ env.is_platform_enabled == 'true' }}
run: rm -rf tmp; mkdir -p tmp/binary '${{ env.app }}'
- name: Install cargo-binstall
if: ${{ env.is_platform_enabled == 'true' }}
uses: cargo-bins/cargo-binstall@main
- name: Install Bevy CLI
if: ${{ env.is_platform_enabled == 'true' }}
run: cargo binstall --locked --no-confirm --force --git='https://github.com/TheBevyFlock/bevy_cli' bevy_cli
- name: Build and add web bundle to app (Web)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'web' }}
run: |
cargo binstall --locked --no-confirm --force wasm-bindgen-cli
cargo binstall --locked --no-confirm --force wasm-opt
bevy build --locked --release --features='${{ matrix.features }}' --yes web --bundle
mv 'target/bevy_web/web-release/${{ env.cargo_build_binary_name }}' '${{ env.app }}'
- name: Build and add binaries to app (non-Web)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform != 'web' }}
run: |
for target in ${{ matrix.targets }}; do
bevy build --locked --release --target="${target}" --features='${{ matrix.features }}'
mv target/"${target}"/release/'${{ env.cargo_build_binary_name }}${{ matrix.binary_ext }}' tmp/binary/"${target}"'${{ matrix.binary_ext }}'
done
if [ '${{ matrix.platform }}' = 'macos' ]; then
lipo tmp/binary/*'${{ matrix.binary_ext }}' -create -output '${{ env.app }}/${{ env.app_binary_name }}${{ matrix.binary_ext }}'
else
mv tmp/binary/*'${{ matrix.binary_ext }}' '${{ env.app }}/${{ env.app_binary_name }}${{ matrix.binary_ext }}'
fi
- name: Add assets to app (non-Web)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform != 'web' }}
run: cp -R ./'${{ env.assets_path }}' '${{ env.app }}' || true # Ignore error if assets folder does not exist.
- name: Add metadata to app (macOS)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'macos' }}
run: |
cat >'${{ env.app }}/../Info.plist' <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${{ env.app_display_name }}</string>
<key>CFBundleExecutable</key>
<string>${{ env.app_binary_name }}</string>
<key>CFBundleIdentifier</key>
<string>${{ env.app_id }}</string>
<key>CFBundleName</key>
<string>${{ env.app_short_name }}</string>
<key>CFBundleShortVersionString</key>
<string>${{ env.version }}</string>
<key>CFBundleVersion</key>
<string>${{ env.version }}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>
EOF
- name: Package app (non-Windows)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform != 'windows' }}
working-directory: tmp/app
run: |
if [ '${{ matrix.platform }}' = 'macos' ]; then
ln -s /Applications .
hdiutil create -fs HFS+ -volname '${{ env.app_package_name }}' -srcfolder . '${{ env.package }}'
else
zip --recurse-paths '${{ env.package }}' '${{ env.app_package_name }}'
fi
- name: Package app (Windows)
if: ${{ env.is_platform_enabled == 'true' && matrix.platform == 'windows' }}
working-directory: tmp/app
shell: pwsh
run: Compress-Archive -Path '${{ env.app_package_name }}' -DestinationPath '${{ env.package }}'
- name: Upload package to workflow artifacts
if: ${{ env.is_platform_enabled == 'true' }}
uses: actions/upload-artifact@v4
with:
path: tmp/app/${{ env.package }}
name: package-${{ matrix.platform }}
retention-days: 1
- name: Upload package to GitHub release
if: ${{ env.is_platform_enabled == 'true' && env.upload_to_github == 'true' }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: tmp/app/${{ env.package }}
asset_name: ${{ env.package }}
release_name: ${{ env.version }}
tag: ${{ env.version }}
overwrite: true
# Upload all packages to itch.io.
upload-to-itch:
runs-on: ubuntu-latest
needs:
- forward-env
- get-version
- build
if: ${{ needs.forward-env.outputs.upload_to_itch != '' }}
steps:
- name: Download all packages
uses: actions/download-artifact@v4
with:
pattern: package-*
path: tmp
- name: Install butler
run: |
curl -L -o butler.zip 'https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default'
unzip butler.zip
chmod +x butler
./butler -V
- name: Upload all packages to itch.io
env:
BUTLER_API_KEY: ${{ secrets.BUTLER_CREDENTIALS }}
run: |
for channel in $(ls tmp); do
./butler push \
--fix-permissions \
--userversion='${{ needs.get-version.outputs.version }}' \
tmp/"${channel}"/* \
'${{ env.upload_to_itch }}':"${channel#package-}"
done
{%- endraw %}

View File

@@ -1,24 +0,0 @@
name: Rust
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install deps
run: sudo apt install libasound2-dev libudev-dev
- name: Build
run: cargo build
- name: Run tests
run: cargo test

View File

@@ -1,3 +1,5 @@
# Phos # Phos
You play as a robot colonizer that has been sent out to an alien planet with one goal. Harvest its resources and send them back home. To accomplish this you must build a base on the planet. As your base develops you will be able to build more advanced structures to harvest at an increased scale. And eventually you will be able to accomplish your goal of sending resources back to your mother planet. But your invasion wont go unchallenged. The native inhabitants of the planet wont sit idly by as you strip their world of its resources. You play as a robot colonizer that has been sent out to an alien planet with one goal. Harvest its resources and send them back home. To accomplish this you must build a base on the planet. As your base develops you will be able to build more advanced structures to harvest at an increased scale. And eventually you will be able to accomplish your goal of sending resources back to your mother planet. But your invasion wont go unchallenged. The native inhabitants of the planet wont sit idly by as you strip their world of its resources.
![development screenshot](https://aoba.app/m/69bafe2f7c042ee871b94dcf)

View File

@@ -1,17 +1,20 @@
use asset_loader::create_asset_loader; use asset_loader::create_asset_loader;
use bevy::{ use bevy::{
ecs::relationship::RelatedSpawnerCommands,
gltf::{GltfMesh, GltfNode}, gltf::{GltfMesh, GltfNode},
prelude::*, prelude::*,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use shared::identifiers::ResourceIdentifier; use shared::{component_defination::ComponentDefination, identifiers::ResourceIdentifier};
use crate::{ use crate::{
buildings::{ buildings::{
conduit_building::ResourceConduitInfo, factory_building::FactoryBuildingInfo, basic_building::BasicBuildingInfo, conduit_building::ResourceConduitInfo,
resource_gathering::ResourceGatheringBuildingInfo, factory_building::FactoryBuildingInfo, resource_gathering::ResourceGatheringBuildingInfo,
tech_building::TechBuildingInfo,
}, },
footprint::BuildingFootprint, footprint::BuildingFootprint,
prelude::Building,
}; };
#[derive(Asset, TypePath, Debug, Serialize, Deserialize)] #[derive(Asset, TypePath, Debug, Serialize, Deserialize)]
@@ -32,7 +35,7 @@ pub struct BuildingAsset
pub health: u32, pub health: u32,
pub building_type: BuildingType, pub building_type: BuildingType,
// pub components: Option<Vec<ComponentDefination>>, pub components: Option<Vec<ComponentDefination>>,
} }
impl BuildingAsset impl BuildingAsset
@@ -48,87 +51,101 @@ impl BuildingAsset
nodes: &Assets<GltfNode>, nodes: &Assets<GltfNode>,
) -> Option<Entity> ) -> Option<Entity>
{ {
todo!("Update building spawning"); let base_node = &gltf.named_nodes[&self.base_mesh_path.clone().into_boxed_str()];
// let base_node = &gltf.named_nodes[&self.base_mesh_path.clone().into_boxed_str()]; if let Some(node) = nodes.get(base_node.id()) {
// if let Some(node) = nodes.get(base_node.id()) { if let Some(mesh_handle) = &node.mesh {
// if let Some(mesh_handle) = &node.mesh { if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) {
// if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) { if let Some(primitive) = gltf_mesh.primitives.first() {
// let (mesh, mat) = gltf_mesh.unpack(); let mesh = primitive.mesh.clone();
// let mut entity = commands.spawn(( let mat = primitive
// Mesh3d(mesh), .material
// MeshMaterial3d(mat), .clone()
// Transform::from_translation(pos).with_rotation(rot), .expect(format!("Mesh '{}' does not have a meterial", primitive.name.as_str()).as_str());
// Building, let mut entity = commands.spawn((
// )); Mesh3d(mesh),
// entity.with_children(|b| { MeshMaterial3d(mat),
// for child in &node.children { Transform::from_translation(pos).with_rotation(rot),
// let child_node = nodes.get(child.id()); Building,
// if child_node.is_none() { ));
// continue; entity.with_children(|b| {
// } for child in &node.children {
// self.process_node(child_node.unwrap(), meshes, nodes, b, &node.name); let child_node = nodes.get(child.id());
// } if child_node.is_none() {
// }); continue;
// if let Some(component) = self.get_component_def(&format!("/{0}", &node.name)) { }
// component.apply(&mut entity); self.process_node(child_node.unwrap(), meshes, nodes, b, &node.name);
// } }
// return Some(entity.id()); });
// } if let Some(component) = self.get_component_def(&format!("/{0}", &node.name)) {
// } component.apply(&mut entity);
// } }
// return None; return Some(entity.id());
}
}
}
}
return None;
} }
// fn process_node( fn process_node(
// &self, &self,
// node: &GltfNode, node: &GltfNode,
// meshes: &Assets<GltfMesh>, meshes: &Assets<GltfMesh>,
// nodes: &Assets<GltfNode>, nodes: &Assets<GltfNode>,
// commands: &mut ChildBuilder, commands: &mut RelatedSpawnerCommands<ChildOf>,
// parent: &String, parent: &String,
// ) -> Option<Entity> { ) -> Option<Entity>
// let path = format!("{0}/{1}", parent, node.name); {
// if let Some(mesh) = &node.mesh { let path = format!("{0}/{1}", parent, node.name);
// if let Some(gltf_mesh) = meshes.get(mesh.id()) { if let Some(mesh) = &node.mesh {
// let (mesh, mat) = gltf_mesh.unpack(); if let Some(gltf_mesh) = meshes.get(mesh.id()) {
// let mut entity = commands.spawn((Mesh3d(mesh), MeshMaterial3d(mat), node.transform, Building)); if let Some(primitive) = gltf_mesh.primitives.first() {
// entity.with_children(|b| { let mesh = primitive.mesh.clone();
// for child in &node.children { let mat = primitive
// let child_node = nodes.get(child.id()); .material
// if child_node.is_none() { .clone()
// continue; .expect(format!("Mesh '{}' does not have a meterial", primitive.name.as_str()).as_str());
// } let mut entity = commands.spawn((Mesh3d(mesh), MeshMaterial3d(mat), node.transform, Building));
// self.process_node(child_node.unwrap(), meshes, nodes, b, &path); entity.with_children(|b| {
// } for child in &node.children {
// }); let child_node = nodes.get(child.id());
// if let Some(component) = self.get_component_def(&path) { if child_node.is_none() {
// component.apply(&mut entity); continue;
// } }
// return Some(entity.id()); self.process_node(child_node.unwrap(), meshes, nodes, b, &path);
// } }
// } });
// return None; if let Some(component) = self.get_component_def(&path) {
// } component.apply(&mut entity);
}
return Some(entity.id());
}
}
}
return None;
}
// fn get_component_def(&self, path: &String) -> Option<&ComponentDefination> { fn get_component_def(&self, path: &String) -> Option<&ComponentDefination>
// if let Some(components) = &self.components { {
// for c in components { if let Some(components) = &self.components {
// if c.path.ends_with(path) { for c in components {
// return Some(c); if c.path.ends_with(path) {
// } return Some(c);
// } }
// } }
// return None; }
// } return None;
}
} }
#[derive(Serialize, Deserialize, Debug, TypePath)] #[derive(Serialize, Deserialize, Debug, TypePath)]
pub enum BuildingType pub enum BuildingType
{ {
Basic, Basic(BasicBuildingInfo),
Gathering(ResourceGatheringBuildingInfo), Gathering(ResourceGatheringBuildingInfo),
FactoryBuildingInfo(FactoryBuildingInfo), FactoryBuildingInfo(FactoryBuildingInfo),
ResourceConduit(ResourceConduitInfo), ResourceConduit(ResourceConduitInfo),
Tech(TechBuildingInfo),
} }
create_asset_loader!( create_asset_loader!(

View File

@@ -1,3 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct BasicBuildingInfo {} pub struct BasicBuildingInfo
{
health: u32,
}

View File

@@ -32,6 +32,7 @@ hex = { path = "../../engine/hex" }
# bevy_lunex = "0.2.4" # bevy_lunex = "0.2.4"
[features] [features]
editor = []
tracing = [ tracing = [
"bevy/trace_tracy", "bevy/trace_tracy",
"world_generation/tracing", "world_generation/tracing",

View File

@@ -1,4 +1,5 @@
use bevy::anti_alias::taa::TemporalAntiAliasing; use bevy::anti_alias::taa::TemporalAntiAliasing;
use bevy::camera::visibility::RenderLayers;
use bevy::core_pipeline::prepass::DepthPrepass; use bevy::core_pipeline::prepass::DepthPrepass;
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel}; use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
use bevy::prelude::*; use bevy::prelude::*;
@@ -53,10 +54,8 @@ fn setup(mut commands: Commands)
PhosOrbitCamera::default(), PhosOrbitCamera::default(),
TemporalAntiAliasing::default(), TemporalAntiAliasing::default(),
)) ))
.insert(Msaa::Off); .insert(Msaa::Off)
// .insert(RenderLayers::layer(0)) .insert(RenderLayers::default());
// *msaa = Msaa::Off;
} }
fn orbit_camera_upate( fn orbit_camera_upate(

View File

@@ -2,7 +2,6 @@ use crate::camera_system::components::PhosCamera;
use crate::map_rendering::map_init::MapInitPlugin; use crate::map_rendering::map_init::MapInitPlugin;
use crate::map_rendering::render_distance_system::RenderDistancePlugin; use crate::map_rendering::render_distance_system::RenderDistancePlugin;
use crate::ui::build_ui::BuildUIPlugin; use crate::ui::build_ui::BuildUIPlugin;
use crate::utlis::editor_plugin::EditorPlugin;
use crate::utlis::tile_selection_plugin::TileSelectionPlugin; use crate::utlis::tile_selection_plugin::TileSelectionPlugin;
use crate::{camera_system::camera_plugin::PhosCameraPlugin, utlis::debug_plugin::DebugPlugin}; use crate::{camera_system::camera_plugin::PhosCameraPlugin, utlis::debug_plugin::DebugPlugin};
use bevy::diagnostic::{EntityCountDiagnosticsPlugin, FrameTimeDiagnosticsPlugin}; use bevy::diagnostic::{EntityCountDiagnosticsPlugin, FrameTimeDiagnosticsPlugin};
@@ -12,13 +11,9 @@ use bevy_asset_loader::prelude::*;
use bevy_rapier3d::dynamics::{Ccd, RigidBody, Velocity}; use bevy_rapier3d::dynamics::{Ccd, RigidBody, Velocity};
use bevy_rapier3d::geometry::Collider; use bevy_rapier3d::geometry::Collider;
use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin}; use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin};
// use buildings::BuildingPugin;
// use iyes_perf_ui::prelude::*;
// use shared::animation_plugin::SimpleAnimationPlugin;
use shared::sets::GameplaySet; use shared::sets::GameplaySet;
use shared::states::{GameplayState, MenuState}; use shared::states::{GameplayState, MenuState};
use shared::{despawn::DespawnPuglin, states::AssetLoadState}; use shared::{despawn::DespawnPuglin, states::AssetLoadState};
// use units::units_plugin::UnitsPlugin;
use world_generation::states::GeneratorState; use world_generation::states::GeneratorState;
pub struct PhosGamePlugin; pub struct PhosGamePlugin;
@@ -45,8 +40,8 @@ impl Plugin for PhosGamePlugin
// UnitsPlugin, // UnitsPlugin,
DespawnPuglin, DespawnPuglin,
TileSelectionPlugin, TileSelectionPlugin,
#[cfg(debug_assertions)] #[cfg(feature = "editor")]
EditorPlugin, crate::utlis::editor_plugin::EditorPlugin,
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
DebugPlugin, DebugPlugin,
)); ));
@@ -146,8 +141,7 @@ fn spawn_sphere(
mat: Res<SphereMat>, mat: Res<SphereMat>,
) )
{ {
if keyboard_input.just_pressed(KeyCode::KeyF) if keyboard_input.just_pressed(KeyCode::KeyF) {
{
commands.spawn(( commands.spawn((
Mesh3d(meshes.add(Sphere::new(0.3))), Mesh3d(meshes.add(Sphere::new(0.3))),
MeshMaterial3d(mat.0.clone()), MeshMaterial3d(mat.0.clone()),

View File

@@ -1,39 +1,223 @@
use bevy::{camera::visibility::RenderLayers, prelude::*}; use bevy::{
camera::{visibility::RenderLayers, CameraOutputMode},
prelude::*,
render::render_resource::BlendState,
};
use shared::states::AssetLoadState; use shared::states::AssetLoadState;
use crate::ui::states::BuildUIState;
pub struct BuildUIPlugin; pub struct BuildUIPlugin;
#[derive(Component, Default)]
struct BuildUIItem;
#[derive(Component, Default)]
#[require(BuildUIItem)]
struct BuildUIMenuItem;
#[derive(Component, Default)]
struct BuildMenuRoot;
#[derive(Resource, Reflect, Debug, Default)]
struct BuildUIInfo
{
menu: BuildUIMenu,
}
#[derive(Default, Reflect, Debug)]
enum BuildUIMenu
{
#[default]
Structure,
Defense,
}
impl Plugin for BuildUIPlugin impl Plugin for BuildUIPlugin
{ {
fn build(&self, app: &mut App) fn build(&self, app: &mut App)
{ {
app.add_systems(Startup, setup_cameras); app.add_systems(Startup, setup_cameras);
app.add_systems(Update, spawn_ui.run_if(in_state(AssetLoadState::LoadComplete))); app.init_resource::<BuildUIInfo>();
app.insert_state(BuildUIState::Init);
app.add_systems(
Update,
(
spawn_ui.run_if(in_state(AssetLoadState::LoadComplete).and(in_state(BuildUIState::Init))),
draw_menu_ui.run_if(in_state(AssetLoadState::LoadComplete).and(in_state(BuildUIState::DrawMenu))),
),
);
app.add_systems(PostUpdate, cleanup_ui.run_if(in_state(BuildUIState::Cleanup)));
} }
} }
fn setup_cameras(mut commands: Commands) fn setup_cameras(mut commands: Commands)
{ {
commands.spawn((Camera2d, IsDefaultUiCamera, RenderLayers::layer(2))); commands
.spawn((
Camera2d,
Camera {
order: 1,
clear_color: ClearColorConfig::None,
msaa_writeback: MsaaWriteback::Always,
output_mode: CameraOutputMode::Write {
blend_state: Some(BlendState::ALPHA_BLENDING),
clear_color: ClearColorConfig::None,
},
..default()
},
IsDefaultUiCamera,
))
.insert(RenderLayers::layer(1))
.insert(Msaa::Off);
} }
fn spawn_ui(mut commands: Commands) fn spawn_ui(mut commands: Commands, mut next_state: ResMut<NextState<BuildUIState>>)
{ {
commands commands
.spawn((Node { .spawn((
width: Val::Percent(100.), Node {
height: Val::Percent(100.), width: Val::Percent(100.),
justify_content: JustifyContent::Center, height: Val::Percent(100.),
align_items: AlignItems::End, justify_content: JustifyContent::Center,
..default() align_items: AlignItems::End,
},)) ..default()
},
RenderLayers::layer(1),
Name::new("Build UI Root"),
BuildUIItem,
))
// .insert(PickingBehavior::IGNORE) // .insert(PickingBehavior::IGNORE)
.with_children(|parent| { .with_children(|build_root| {
parent.spawn(( build_root
Node { .spawn((
width: Val::Px(500.), Name::new("Build UI"),
..Default::default() Node {
}, width: Val::Px(500.),
BackgroundColor(LinearRgba::GREEN.into()), height: Val::Px(100.),
)); justify_content: JustifyContent::Stretch,
flex_direction: FlexDirection::Column,
..default()
},
BackgroundColor(LinearRgba::GREEN.into()),
))
.with_children(|build_ui| {
build_ui.spawn((
Name::new("Menu Root"),
BuildMenuRoot,
Node {
width: Val::Percent(100.),
height: Val::Px(70.),
column_gap: Val::Px(5.),
padding: UiRect::all(Val::Px(2.)),
flex_direction: FlexDirection::Row,
overflow: Overflow::scroll_x(),
..default()
},
));
build_ui
.spawn((
Name::new("Toolbar"),
Node {
width: Val::Percent(100.),
height: Val::Px(30.),
column_gap: Val::Px(5.),
padding: UiRect::horizontal(Val::Px(10.)),
justify_content: JustifyContent::Stretch,
align_self: AlignSelf::End,
..default()
},
BackgroundColor(LinearRgba::BLUE.into()),
))
.with_children(|toolbar| {
for i in 0..6
{
toolbar.spawn((
Name::new(format!("Button {}", i)),
Button,
Node {
height: Val::Percent(100.),
width: Val::Percent(100.),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..default()
},
BackgroundColor(LinearRgba::WHITE.into()),
children![(
Text::new(format!("Button {}", i)),
TextFont {
font_size: 15.,
..default()
},
TextColor(LinearRgba::BLACK.into()),
TextShadow {
offset: Vec2::splat(2.),
..default()
}
)],
));
}
});
});
}); });
next_state.set(BuildUIState::DrawMenu);
}
fn draw_menu_ui(
mut commands: Commands,
menu_root: Single<Entity, With<BuildMenuRoot>>,
menu_items: Query<Entity, With<BuildUIMenuItem>>,
menu_info: Res<BuildUIInfo>,
mut next: ResMut<NextState<BuildUIState>>,
)
{
for entity in menu_items.iter()
{
commands.entity(entity).despawn();
}
info!("Draw Menu");
match menu_info.menu
{
BuildUIMenu::Structure => draw_structure_ui(commands, menu_root.into_inner()),
BuildUIMenu::Defense => (),
}
next.set(BuildUIState::Update);
}
fn draw_structure_ui(mut commands: Commands, root: Entity)
{
commands.entity(root).with_children(|root| {
for i in 0..10
{
root.spawn((
BuildUIMenuItem,
Node {
height: Val::Percent(100.),
width: Val::Px(100.),
display: Display::Grid,
grid_template_rows: vec![RepeatedGridTrack::px(1, 100.), RepeatedGridTrack::fr(1, 1.)],
..default()
},
children![
(
Node {
height: Val::Px(100.),
width: Val::Px(100.),
..default()
},
BackgroundColor(LinearRgba::RED.into())
),
(Text::new(format!("Icon {}", i))),
],
));
}
});
}
fn cleanup_ui(mut commands: Commands, ui_items: Query<Entity, With<BuildUIItem>>)
{
for entity in ui_items.iter()
{
commands.entity(entity).despawn();
}
} }

View File

@@ -1 +1,2 @@
pub mod build_ui; pub mod build_ui;
pub mod states;

View File

@@ -0,0 +1,10 @@
use bevy::prelude::*;
#[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
pub enum BuildUIState
{
Init,
DrawMenu,
Update,
Cleanup,
}

View File

@@ -1,6 +1,6 @@
use bevy::asset::RenderAssetUsages; use bevy::asset::RenderAssetUsages;
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::bevy_egui::EguiContexts; use bevy_inspector_egui::bevy_egui::{EguiContexts, EguiTextureHandle};
use bevy_inspector_egui::egui::{self}; use bevy_inspector_egui::egui::{self};
use image::{ImageBuffer, Rgba}; use image::{ImageBuffer, Rgba};
use world_generation::biome_asset::BiomeAsset; use world_generation::biome_asset::BiomeAsset;
@@ -92,14 +92,14 @@ fn asset_reloaded(
} }
fn render_map_ui( fn render_map_ui(
// image: Res<MapImage>, image: Res<MapImage>,
heightmap: Res<Map>, heightmap: Res<Map>,
biome_map: Res<BiomeMap>, biome_map: Res<BiomeMap>,
mut contexts: EguiContexts, mut contexts: EguiContexts,
mut state: ResMut<UIState>, mut state: ResMut<UIState>,
) )
{ {
// let id = contexts.add_image(image.0.); let id = contexts.add_image(EguiTextureHandle::Weak(image.0.id()));
let mut map_type = state.target_map_type; let mut map_type = state.target_map_type;
let ctx = contexts.ctx_mut().expect("Failed to get egui context"); let ctx = contexts.ctx_mut().expect("Failed to get egui context");
egui::Window::new("Map").open(&mut state.is_open).show(ctx, |ui| { egui::Window::new("Map").open(&mut state.is_open).show(ctx, |ui| {
@@ -127,10 +127,10 @@ fn render_map_ui(
); );
}); });
// ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new( ui.add(egui::widgets::Image::new(egui::load::SizedTexture::new(
// id, id,
// [512.0, 512.0], [512.0, 512.0],
// ))); )));
if ui.button("Save Image").clicked() if ui.button("Save Image").clicked()
{ {

View File

@@ -1,4 +1,5 @@
pub mod chunk_utils; pub mod chunk_utils;
pub mod debug_plugin; pub mod debug_plugin;
#[cfg(feature = "editor")]
pub mod editor_plugin; pub mod editor_plugin;
pub mod tile_selection_plugin; pub mod tile_selection_plugin;

View File

@@ -1,18 +1,18 @@
use bevy::{ use bevy::{ecs::system::EntityCommands, prelude::*};
ecs::system::EntityCommands, math::{Quat, Vec3}, prelude::*
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::prefab_defination::AnimationComponent; use crate::prefab_defination::AnimationComponent;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct ComponentDefination { pub struct ComponentDefination
{
pub path: String, pub path: String,
pub animations: Vec<AnimationComponent>, pub animations: Vec<AnimationComponent>,
} }
impl ComponentDefination
impl ComponentDefination { {
pub fn apply(&self, commands: &mut EntityCommands){ pub fn apply(&self, commands: &mut EntityCommands)
{
for c in &self.animations { for c in &self.animations {
c.apply(commands); c.apply(commands);
} }

View File

@@ -1,18 +1,18 @@
use bevy::reflect::Reflect; use bevy::reflect::Reflect;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod animation_plugin;
pub mod building; pub mod building;
pub mod component_defination;
pub mod coords; pub mod coords;
pub mod despawn; pub mod despawn;
pub mod events; pub mod events;
pub mod identifiers; pub mod identifiers;
pub mod prefab_defination;
pub mod resources; pub mod resources;
pub mod sets; pub mod sets;
pub mod states; pub mod states;
pub mod tags; pub mod tags;
// pub mod prefab_defination;
// pub mod animation_plugin;
// pub mod component_defination;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum Tier pub enum Tier

View File

@@ -1,12 +1,13 @@
use bevy::{ use bevy::{
ecs::system::{EntityCommand, EntityCommands}, ecs::{relationship::RelatedSpawnerCommands, system::EntityCommands},
gltf::{Gltf, GltfMesh}, gltf::{Gltf, GltfMesh},
math::{Quat, Vec3}, math::{Quat, Vec3},
prelude::*, prelude::*,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct PrefabDefination { pub struct PrefabDefination
{
pub path: String, pub path: String,
pub pos: Vec3, pub pos: Vec3,
pub rot: Vec3, pub rot: Vec3,
@@ -14,38 +15,54 @@ pub struct PrefabDefination {
pub animations: Option<Vec<AnimationComponent>>, pub animations: Option<Vec<AnimationComponent>>,
} }
impl PrefabDefination { impl PrefabDefination
pub fn spawn_recursive(&self, gltf: &Gltf, commands: &mut ChildBuilder, meshes: &Assets<GltfMesh>) { {
pub fn spawn_recursive(
&self,
gltf: &Gltf,
commands: &mut RelatedSpawnerCommands<ChildOf>,
meshes: &Assets<GltfMesh>,
)
{
let mesh_handle = &gltf.named_meshes[&self.path.clone().into_boxed_str()]; let mesh_handle = &gltf.named_meshes[&self.path.clone().into_boxed_str()];
if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) { if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) {
let (m, mat) = gltf_mesh.unpack(); if let Some(primitive) = gltf_mesh.primitives.first() {
let mut entity = commands.spawn(( let mesh = primitive.mesh.clone();
Mesh3d(m), let mat = primitive
MeshMaterial3d(mat), .material
Transform::from_translation(self.pos).with_rotation(Quat::from_euler( .clone()
bevy::math::EulerRot::XYZ, .expect(format!("Mesh '{}' does not have a meterial", primitive.name.as_str()).as_str());
self.rot.x, let mut entity = commands.spawn((
self.rot.y, Mesh3d(mesh),
self.rot.z, MeshMaterial3d(mat),
)), Transform::from_translation(self.pos).with_rotation(Quat::from_euler(
)); bevy::math::EulerRot::XYZ,
if let Some(children) = &self.children { self.rot.x,
entity.with_children(|b| { self.rot.y,
for child in children { self.rot.z,
child.spawn_recursive(gltf, b, meshes); )),
} ));
}); if let Some(children) = &self.children {
entity.with_children(|b| {
for child in children {
child.spawn_recursive(gltf, b, meshes);
}
});
}
} }
} }
} }
} }
pub trait UnpackGltfMesh { pub trait UnpackGltfMesh
{
fn unpack(&self) -> (Handle<Mesh>, Handle<StandardMaterial>); fn unpack(&self) -> (Handle<Mesh>, Handle<StandardMaterial>);
} }
impl UnpackGltfMesh for GltfMesh { impl UnpackGltfMesh for GltfMesh
fn unpack(&self) -> (Handle<Mesh>, Handle<StandardMaterial>) { {
fn unpack(&self) -> (Handle<Mesh>, Handle<StandardMaterial>)
{
let p = &self.primitives[0]; let p = &self.primitives[0];
let mut mat: Handle<StandardMaterial> = default(); let mut mat: Handle<StandardMaterial> = default();
if let Some(mesh_material) = &p.material { if let Some(mesh_material) = &p.material {
@@ -56,19 +73,23 @@ impl UnpackGltfMesh for GltfMesh {
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub enum AnimationComponent { pub enum AnimationComponent
{
Rotation(RotationAnimation), Rotation(RotationAnimation),
Slider, Slider,
} }
#[derive(Serialize, Deserialize, Debug, Component, Clone, Copy)] #[derive(Serialize, Deserialize, Debug, Component, Clone, Copy)]
pub struct RotationAnimation { pub struct RotationAnimation
{
pub axis: Vec3, pub axis: Vec3,
pub speed: f32, pub speed: f32,
} }
impl AnimationComponent { impl AnimationComponent
pub fn apply(&self, commands: &mut EntityCommands) { {
pub fn apply(&self, commands: &mut EntityCommands)
{
match self { match self {
AnimationComponent::Rotation(comp) => { AnimationComponent::Rotation(comp) => {
commands.insert(comp.clone()); commands.insert(comp.clone());

View File

@@ -1,7 +1,8 @@
use bevy::prelude::*; use bevy::prelude::*;
#[derive(States, Debug, Clone, PartialEq, Eq, Hash)] #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
pub enum MenuState { pub enum MenuState
{
Loading, Loading,
Startup, Startup,
MainMenu, MainMenu,
@@ -10,14 +11,16 @@ pub enum MenuState {
} }
#[derive(States, Debug, Clone, PartialEq, Eq, Hash)] #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
pub enum GameplayState { pub enum GameplayState
{
Waiting, Waiting,
PlaceHQ, PlaceHQ,
Playing, Playing,
} }
#[derive(States, Debug, Clone, PartialEq, Eq, Hash)] #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
pub enum AssetLoadState { pub enum AssetLoadState
{
Loading, Loading,
FinalizeAssets, FinalizeAssets,
LoadComplete, LoadComplete,

View File

@@ -1,4 +1,3 @@
hard_tabs = true hard_tabs = true
max_width = 120 max_width = 120
brace_style = "AlwaysNextLine" brace_style = "AlwaysNextLine"
control_brace_style = "AlwaysNextLine"