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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions .github/workflows/dist_linux.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Build on Linux
on: push

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-22.04
Expand All @@ -12,16 +16,14 @@ jobs:
- name: Install Nim
run: |
cd $HOME &&
curl -O https://nim-lang.org/download/nim-2.2.0-linux_x64.tar.xz &&
tar xf nim-2.2.0-linux_x64.tar.xz
- name: Install Nim and build deps
curl -O https://nim-lang.org/download/nim-2.2.6-linux_x64.tar.xz &&
tar xf nim-2.2.6-linux_x64.tar.xz
- name: Install build deps
run: |
sudo apt-get update
sudo apt-get install build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libfuse2
- name: Update path
run: echo "$HOME/.nimble/bin:$HOME/nim-2.2.0/bin" >> $GITHUB_PATH
- name: Install nimble deps
run: nimble setup -y
run: echo "$HOME/nim-2.2.6/bin" >> $GITHUB_PATH
- name: Save SHAs of submodules
run: 'git submodule status > .submodules.tmp'
- name: Prep dist config
Expand All @@ -33,12 +35,23 @@ jobs:
path: |
vendor/godot/bin
fonts
key: ${{ runner.os }}-prereq-cache-v4-${{ hashFiles('.submodules.tmp') }}
deps
key: ${{ runner.os }}-prereq-cache-v5-${{ hashFiles('.submodules.tmp', 'atlas.lock') }}
- name: build prereqs
run: nimble dist_prereqs
run: nim dist_prereqs
if: steps.prereq-cache.outputs.cache-hit != 'true'
- name: Setup package paths
run: atlas rep
- name: Dist
run: nimble dist_package
run: nim dist_package
- name: Run unit tests
run: nim unit_tests
- name: Run VM tests
run: nim vm_tests
- name: Rebuild for headless tests
run: nim build
- name: Run world tests
run: nim world_tests headless
- uses: actions/upload-artifact@v4
with:
name: Enu Linux Distribution
Expand Down
31 changes: 20 additions & 11 deletions .github/workflows/dist_mac.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Build on macOS
on: push

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: macos-latest
Expand Down Expand Up @@ -42,16 +46,12 @@ jobs:
xcrun notarytool store-credentials "$NOTARIZATION_PROFILE" --apple-id "$NOTARIZATION_APPLE_ID" --team-id "$NOTARIZATION_TEAM_ID" --password "$NOTARIZATION_PWD"

- name: Install build deps
run: brew install nim scons yasm
run: brew install scons yasm
- name: Install nim
run: |
curl -LO https://github.com/nim-lang/nightlies/releases/download/2024-10-02-version-2-2-78983f1876726a49c69d65629ab433ea1310ece1/nim-2.2.0-macosx_x64.tar.xz
tar xzf nim-2.2.0-macosx_x64.tar.xz
echo "$(pwd)/nim-2.2.0/bin" >> $GITHUB_PATH
- name: Update path
run: echo "$HOME/.nimble/bin" >> $GITHUB_PATH
- name: Install nimble deps
run: nimble setup -y
curl -LO https://github.com/nim-lang/nightlies/releases/download/2025-10-31-version-2-2-ab00c56904e3126ad826bb520d243513a139436a/nim-2.2.6-macosx_arm64.tar.xz
tar xzf nim-2.2.6-macosx_arm64.tar.xz
echo "$(pwd)/nim-2.2.6/bin" >> $GITHUB_PATH
- name: Save SHAs of submodules
run: "git submodule status > .submodules.tmp"
- name: prereq cache
Expand All @@ -61,12 +61,21 @@ jobs:
path: |
vendor/godot/bin
fonts
key: ${{ runner.os }}-prereq-cache-v2-${{ hashFiles('.submodules.tmp') }}
deps
key: ${{ runner.os }}-prereq-cache-v5-${{ hashFiles('.submodules.tmp', 'atlas.lock') }}
- name: build prereqs
run: nimble dist_prereqs
run: nim dist_prereqs
if: steps.prereq-cache.outputs.cache-hit != 'true'
- name: Setup package paths
run: atlas rep
- name: Dist
run: nimble dist_package
run: nim dist_package
- name: Run unit tests
run: nim unit_tests
- name: Run VM tests
run: nim vm_tests
- name: Run world tests
run: nim world_tests dist
- uses: actions/upload-artifact@v4
with:
name: Enu macOS Distribution
Expand Down
33 changes: 22 additions & 11 deletions .github/workflows/dist_win.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Build on Windows
on: push

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: windows-2022
Expand All @@ -13,21 +17,19 @@ jobs:
- name: Install Nim
run: |
cd ${HOME}
C:\msys64\usr\bin\wget.exe https://nim-lang.org/download/nim-2.2.4_x64.zip
7z.exe x nim-2.2.4_x64.zip -y
C:\msys64\usr\bin\wget.exe https://nim-lang.org/download/nim-2.2.6_x64.zip
7z.exe x nim-2.2.6_x64.zip -y
- name: Install build deps
run: choco install yasm innosetup rcedit zip reshack
- name: Install scons
run: python -m pip install scons
- name: Update path
run: echo "${HOME}/.nimble/bin;${HOME}/nim-2.2.4/bin;C:\msys64\mingw64\bin;C:\Program Files (x86)\Resource Hacker" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Configure git for nimble
run: echo "${HOME}/nim-2.2.6/bin;C:\msys64\mingw64\bin;C:\Program Files (x86)\Resource Hacker" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Configure git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
git config --global core.symlinks false
- name: Install nimble deps
run: nimble setup -y
- name: Save SHAs of submodules
run: 'git submodule status > .submodules.tmp'
- name: Prep dist config
Expand All @@ -40,9 +42,10 @@ jobs:
path: |
vendor/godot/bin
fonts
key: ${{ runner.os }}-prereq-cache-v4-${{ hashFiles('.submodules.tmp') }}
deps
key: ${{ runner.os }}-prereq-cache-v5-${{ hashFiles('.submodules.tmp', 'atlas.lock') }}
- name: build prereqs
run: nimble dist_prereqs
run: nim dist_prereqs
if: steps.prereq-cache.outputs.cache-hit != 'true'
- name: Download and copy mesa
# github runner doesn't have a GPU, so we need to link to mesa
Expand All @@ -56,9 +59,17 @@ jobs:
cd ..
rm mesa -Recurse
if: steps.prereq-cache.outputs.cache-hit != 'true'

- name: Setup package paths
run: atlas rep
- name: Dist
run: nimble dist_package
run: nim dist_package
- name: Run unit tests
run: nim unit_tests
- name: Run VM tests
run: nim vm_tests
# world_tests disabled on Windows - no headless support until Godot 4
# - name: Run world tests
# run: nim world_tests dist

# Upload unsigned dist for zip signing
- name: Upload unsigned dist for zip signing
Expand Down Expand Up @@ -95,7 +106,7 @@ jobs:

# Rebuild installer with signed files
- name: Rebuild installer with signed files
run: nimble build_installer
run: nim build_installer

# Upload unsigned installer for signing
- name: Upload unsigned installer for signing
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ nimble.develop
nimble.paths
/t.nim
fonts/
nimbledeps/
.submodules.tmp

*.previous
.claude/
deps/
nimbledeps/
nim.cfg
.build_arch
43 changes: 26 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,35 @@ Enu is a 3D sandbox environment for creating and exploring voxel worlds using a

## Build Commands

### Setup
- `atlas install && atlas rep` - Install dependencies (first-time setup)
- `nim prereqs` - Build Godot, download fonts, generate API bindings and stdlib

### Core Development Commands
- `nimble build` - Build the main application (required after code changes)
- `nimble prereqs` - Build Godot, download fonts, generate API bindings and stdlib (first-time setup)
- `nimble start` - Run Enu in development mode
- `nimble build_and_start` - Build and run in one command
- `nimble edit` - Open project in Godot editor
- `nim build` - Build the main application (required after code changes)
- `nim start` - Run Enu in development mode
- `nim build_and_start` - Build and run in one command
- `nim edit` - Open project in Godot editor

### Distribution and Packaging
- `nimble dist` - Build complete distribution package for current platform
- `nimble dist_prereqs` - Build debug/release Godot versions and fonts
- `nimble dist_package` - Package distribution binaries
- `nim dist` - Build complete distribution package for current platform
- `nim dist_prereqs` - Build debug/release Godot versions and fonts
- `nim dist_package` - Package distribution binaries

### Testing and Documentation
- `nimble test` - Run Godot-based tests
- `nimble docs` - Build documentation using nimibook
- `nimble clean` - Remove build artifacts
- `nim test` - Run all tests
- `nim unit_tests` - Run unit tests
- `nim vm_tests` - Run VM script tests
- `nim docs` - Build documentation using nimibook
- `nim clean` - Remove build artifacts

### Platform-Specific
- `nimble ios` - Build iOS package
- `nimble ios_prereqs` - Build Godot for iOS (requires macOS)
- `nim ios` - Build iOS package
- `nim ios_prereqs` - Build Godot for iOS (requires macOS)

### Cross-Architecture Builds (Linux)

Pass `amd64` or `arm64` to `nim prereqs` to set the target architecture. See `docs/notes/linux-cross-compile.md` for detailed setup instructions and required packages.

## Architecture

Expand Down Expand Up @@ -68,7 +77,7 @@ Enu is a 3D sandbox environment for creating and exploring voxel worlds using a

**VM Integration**: User scripts run in the Nim VM, isolated from the main application. The VM has access to a curated API through `vmlib/enu/`.

**Godot Binding**: Uses nim-godot with auto-generated bindings from Godot 3.5 API. Generated code uses `camelCase` but project convention is `snake_case`.
**Godot Binding**: Uses nim-godot with auto-generated bindings from Godot 3.5 API. Use `snake_case` when calling these bindings.

**Model-View Architecture**:
- Models handle data and state (using model_citizen library)
Expand All @@ -77,14 +86,14 @@ Enu is a 3D sandbox environment for creating and exploring voxel worlds using a

### Important Notes

- Always use `snake_case` for naming (despite generated bindings using `camelCase`)
- Use `nimble build` to verify changes compile correctly
- **Always use `snake_case` for identifiers.** Nim's identifier normalization means `snake_case` and `camelCase` are equivalent, but this project strictly uses `snake_case`. Only use `lowerCamelCase` when `snake_case` doesn't work, which should only happen with third-party macros that don't properly normalize identifiers.
- Use `nim build` to verify changes compile correctly
- The project uses ZenContext for metrics and threading
- Scripts are Logo-inspired but use Nim syntax
- World data is stored as JSON with accompanying Nim scripts
- If you're not on `main` or a `0.x` branch, try to keep a clean history. Prefer rebasing and ammending commits to keep work in
logical chunks and --force-with-lease push them to origin. Confirm with the user before pulling.
- Don't include "Generated by Claude" or similar in commits. Include a co-authoried by tag. Keep commit messages concise. Try not to include details that are obvious by quickly looking at the diff.
- Never include "Generated by Claude", "Co-Authored-By: Claude", or similar attribution in commits. Keep commit messages concise. Try not to include details that are obvious by quickly looking at the diff.
- If rebasing or squashing commits, confirm with the user before merging 10 or more commits.
- Avoid nil checks, unless there is a known, non-bug reason why something could be nil. Asserting something isn't nil is fine.
- Things that are fairly obvious shouldn't have comments.
3 changes: 2 additions & 1 deletion app/enutest.gdnlib
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ reloadable=true
OSX.64="res://enu-test.dylib"
Windows.64="res://enu-test.dll"
X11.64="res://enu-test.so"
Server.64="res://enu-test.dylib"
Server.64="res://enu-test.so"

[dependencies]

OSX.64=[ ]
Windows.64=[ ]
X11.64=[ ]
Server.64=[ ]
2 changes: 2 additions & 0 deletions app/nimlib.gdnlib
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ reloadable=false
OSX.64="res://enu.dylib"
Windows.64="res://enu.dll"
X11.64="res://enu.so"
Server.64="res://enu.so"
iOS.arm64="res://libenu.a"

[dependencies]

OSX.64=[ ]
Windows.64=[ ]
X11.64=[ ]
Server.64=[ ]
iOS.arm64=[ ]
10 changes: 5 additions & 5 deletions app/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -105,25 +105,25 @@ toggle_mouse_captured={
}
click={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"doubleclick":false,"script":null)
]
}
fire={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"doubleclick":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":6,"pressure":0.0,"pressed":false,"script":null)
]
}
previous={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null)
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"doubleclick":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":45,"physical_scancode":0,"unicode":0,"raw_code":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":4,"pressure":0.0,"pressed":false,"script":null)
]
}
next={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null)
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"doubleclick":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":5,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":61,"physical_scancode":0,"unicode":0,"raw_code":0,"echo":false,"script":null)
]
Expand Down Expand Up @@ -170,7 +170,7 @@ mode_8={
}
remove={
"deadzone": 0.5,
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":2,"pressed":false,"doubleclick":false,"script":null)
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":2,"canceled":false,"pressed":false,"doubleclick":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":7,"pressure":0.0,"pressed":false,"script":null)
]
}
Expand Down
Loading