Skip to content
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Build Android

on:
push:
branches: [ "master", "develop" ]
branches: [ "master", "develop", "refactor/2.0" ]
pull_request:
branches: [ "master", "develop", "release/**", "hotfix/**" ]
branches: [ "master", "develop", "refactor/2.0", "release/**", "hotfix/**" ]

jobs:
build:
Expand All @@ -13,10 +13,10 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: set up JDK 17
- name: set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Build Desktop

on:
push:
branches: [ "master", "develop" ]
branches: [ "master", "develop", "refactor/2.0" ]
pull_request:
branches: [ "master", "develop", "release/**", "hotfix/**" ]
branches: [ "master", "develop", "refactor/2.0", "release/**", "hotfix/**" ]

jobs:
build:
Expand All @@ -13,10 +13,10 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: set up JDK 17
- name: set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/html.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Build Web

on:
push:
branches: [ "master", "develop" ]
branches: [ "master", "develop", "refactor/2.0" ]
pull_request:
branches: [ "master", "develop", "release/**", "hotfix/**" ]
branches: [ "master", "develop", "refactor/2.0", "release/**", "hotfix/**" ]

jobs:
build:
Expand All @@ -13,10 +13,10 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: set up JDK 17
- name: set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/ktlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ name: Ktlint

on:
push:
branches: [ "master", "develop" ]
branches: [ "master", "develop", "refactor/2.0" ]
paths:
- .github/workflows/ktlint.yml
- '**/src/**/*.kt'
- '**.kts'
pull_request:
branches: [ "master", "develop", "release/**", "hotfix/**" ]
branches: [ "master", "develop", "refactor/2.0", "release/**", "hotfix/**" ]
paths:
- .github/workflows/ktlint.yml
- '**/src/**/*.kt'
Expand All @@ -19,14 +19,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: set up JDK 17
- name: set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Check Ktlint with Gradle
run: ./gradlew ktlintCheck buildSrc:ktlintCheck
run: ./gradlew ktlintCheck
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ name: Tests

on:
push:
branches: [ "master", "develop" ]
branches: [ "master", "develop", "refactor/2.0" ]
paths:
- .github/workflows/test.yml
- '**/src/**/*.kt'
- '**.kts'
pull_request:
branches: [ "master", "develop", "release/**", "hotfix/**" ]
branches: [ "master", "develop", "refactor/2.0", "release/**", "hotfix/**" ]
paths:
- .github/workflows/test.yml
- '**/src/**/*.kt'
Expand All @@ -19,10 +19,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: set up JDK 17
- name: set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

Expand Down
9 changes: 0 additions & 9 deletions .travis.yml

This file was deleted.

31 changes: 14 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ All Gradle tasks run via `./gradlew` (use `gradlew.bat` on Windows — note that
# Lint
./gradlew ktlintCheck # check
./gradlew ktlintFormat # auto-format
./gradlew buildSrc:ktlintCheck # CI also runs this for buildSrc

# Tests (JUnit Jupiter)
./gradlew test # run tests across all modules
Expand All @@ -63,19 +62,12 @@ Conventions, derived from the existing tests in `core/common/mvvm` and
mock them or extract the logic under test into a pure helper.
- **kotlinx-coroutines-test** for `runTest` when the unit under test launches
coroutines (see `core/common/mvvm`).
- Test dependencies are referenced through `Dependencies.Test.*` and
`Dependencies.Kotlin.coroutinesTest`. Add the standard block to the module's
`build.gradle.kts`:

```kotlin
testImplementation(Dependencies.Test.junitJupiter)
testRuntimeOnly(Dependencies.Test.junitJupiterEngine)
testRuntimeOnly(Dependencies.Test.junitPlatformLauncher)
testImplementation(Dependencies.Test.mockk) // optional
testImplementation(Dependencies.Kotlin.coroutinesTest) // optional

tasks.test { useJUnitPlatform() }
```
- Test wiring is provided by the `cavedroid.kotlin-library` convention plugin:
applying `id("cavedroid.kotlin-library")` already adds JUnit Jupiter, mockk and
`kotlinx-coroutines-test`, and calls `useJUnitPlatform()`. A module that opts
into the convention does not need to repeat any of that. Test artifacts live in
the version catalog (`libs.junit.jupiter`, `libs.mockk`,
`libs.kotlinx.coroutines.test`, etc.).

When the SUT is heavy (Box2D bodies, RayHandler, Stage), prefer extracting the
testable logic into a pure helper in `core:common` and unit-testing the helper.
Expand Down Expand Up @@ -127,7 +119,12 @@ The `core` graph follows a clean-architecture-ish split. **Module dependencies f
- **`core:gameplay:*`** — cross-cutting systems: `controls`, `physics` (Box2D), `rendering`, plus the swappable lighting backends `lighting-box2d` (Box2DLights — desktop/android/ios) and `lighting-tint` (full-screen day/night tint — web fallback, no per-block lights).
- **`core:gdx`** — top-level integration: the `CaveDroidApplication : Game` class, `MenuScreen`/`GameScreen`/`PauseMenuScreen`, the menu's MVVM-ish navigation framework (`menu/v2/navigation`), and the **two Dagger components** (`ApplicationComponent`, `GameComponent`).

The `buildSrc/` module centralizes versions and exposes ergonomic dependency helpers: each module's `build.gradle.kts` reads almost like a manifest (`useCommonLibs()`, `useDagger()`, `useDomainModules()`, `useGameModules()`, `useLibgdx()`, `useLibKtx()`, `useAutomultibind()`, `useKotlinxSerializationJson()`, etc., defined in `buildSrc/src/main/kotlin/DependencyHandlerExtentions.kt`). When adding dependencies, prefer extending these helpers over inlining versions.
Build logic lives in two places (there is **no `buildSrc/`** anymore):

- **`gradle/libs.versions.toml`** — the version catalog: all versions, libraries, bundles and plugins. Modules reference dependencies as `libs.*` and sibling modules as type-safe project accessors (`projects.core.common`, `projects.core.gameplay.lightingBfs`, …; `enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")`).
- **`build-logic/`** — an included build (wired in `settings.gradle.kts`'s `pluginManagement`) holding the convention (precompiled-script) plugins: `cavedroid.kotlin-library` (Kotlin/JVM 17 + ktlint + JUnit-platform test wiring), `cavedroid.dagger` (applies KSP + binds `dagger`/`dagger-compiler`), `cavedroid.libgdx`, `cavedroid.automultibind`, and `cavedroid.license-report` (applies the jk1 plugin and the default notices renderer; also carries `PerFlavorTextReportRenderer`). A module's `build.gradle.kts` reads like a manifest: `plugins { id("cavedroid.kotlin-library"); id("cavedroid.dagger") }` then `dependencies { implementation(projects.…); implementation(libs.…) }`.

KSP and kotlin-android are applied by **bare `id(...)` (no version)** in modules that also pull a `cavedroid.*` convention — the Kotlin/KSP gradle-plugin markers are already on the classpath via `build-logic`, so a versioned `alias(...)` would clash. `kotlin-serialization` and `construo` use `alias(libs.plugins.*)` (those markers are not on the classpath). When adding dependencies, add them to the catalog and reference `libs.*`; for shared behavior, extend a convention plugin in `build-logic`.

### Dependency injection (Dagger + KSP + automultibind)

Expand All @@ -151,14 +148,14 @@ Both wire into `processResources` / `preBuild` automatically — don't commit th

### Versioning

`buildSrc/src/main/kotlin/ApplicationInfo.kt` (`versionName`, `versionCode`) and `core/common/.../CaveDroidConstants.kt` (`VERSION`) must stay in lockstep. `scripts/up-version.sh <new-version>` is the only sanctioned way to bump them.
App metadata lives in root `gradle.properties` (`cavedroid.appName`, `cavedroid.packageName`, `cavedroid.versionName`, `cavedroid.versionCode`) and is read in build scripts via `providers.gradleProperty(...)`. `cavedroid.versionName`/`cavedroid.versionCode` and `core/common/.../CaveDroidConstants.kt` (`VERSION`) must stay in lockstep. `scripts/up-version.sh <new-version>` is the only sanctioned way to bump them.

### Android product flavors (`foss` vs `store`)

The Android module ships **two flavors** on the `distribution` dimension, declared in `android/build.gradle.kts`:

- **`foss`** — no proprietary deps. Firebase Crashlytics and Yandex Mobile Ads are excluded; the `process*GoogleServices` / `*CrashlyticsMappingFile*` tasks are disabled in `androidComponents { onVariants(... "foss") }`. `BANNER_AD_UNIT_ID` / `INTERSTITIAL_AD_UNIT_ID` BuildConfig fields are `null`.
- **`store`** — bundles Firebase Crashlytics (via `storeImplementation platform(Firebase.bom) + Firebase.crashlytics`) and Yandex Mobile Ads (`Dependencies.Yandex.mobileads`). Ad unit IDs come from `yandex.properties` at repo root (`bannerAdUnitId`, `interstitialAdUnitId`); missing properties fall back to `null` BuildConfig fields.
- **`store`** — bundles Firebase Crashlytics (via `storeImplementation platform(libs.firebase.bom) + libs.firebase.crashlytics`) and Yandex Mobile Ads (`libs.yandex.mobileads`). Ad unit IDs come from `yandex.properties` at repo root (`bannerAdUnitId`, `interstitialAdUnitId`); missing properties fall back to `null` BuildConfig fields.

Build either flavor with `./gradlew :android:assembleFossDebug` or `:android:assembleStoreDebug`. CI/local debug-only flows can still use the convenience `:android:assembleDebug` (assembles both).

Expand Down
86 changes: 43 additions & 43 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import java.util.Properties
private val natives by configurations.creating

plugins {
id("com.android.application")
id("kotlin-android")

id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
alias(libs.plugins.android.application)
alias(libs.plugins.google.services)
alias(libs.plugins.firebase.crashlytics)
id("cavedroid.license-report")
}

private val appPackageName = providers.gradleProperty("cavedroid.packageName").get()
private val appVersionName = providers.gradleProperty("cavedroid.versionName").get()
private val appVersionCode = providers.gradleProperty("cavedroid.versionCode").get().toInt()

private val keystorePropertiesFile = rootProject.file("keystore.properties")
private val keystoreProperties = if (keystorePropertiesFile.exists()) {
Properties().apply {
Expand All @@ -36,35 +39,35 @@ private val yandexProperties = if (yandexPropertiesFile.exists()) {
}

android {
namespace = ApplicationInfo.packageName
namespace = appPackageName
compileSdk = 36

sourceSets {

named("main") {
jniLibs.srcDir("libs")
jniLibs.directories.add("libs")
assets {
srcDirs("src/main/assets", "build/generated/extraRes/shared")
directories.addAll(listOf("src/main/assets", "build/generated/extraRes/shared"))
}
}

named("debug") {
res.srcDir("src/debug/res")
res.directories.add("src/debug/res")
}
}

compileOptions {
sourceCompatibility = ApplicationInfo.sourceCompatibility
targetCompatibility = ApplicationInfo.sourceCompatibility
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

defaultConfig {
applicationId = ApplicationInfo.packageName
applicationId = appPackageName
minSdk = 23
targetSdk = 36

versionCode = ApplicationInfo.versionCode
versionName = ApplicationInfo.versionName
versionCode = appVersionCode
versionName = appVersionName

multiDexEnabled = true
}
Expand Down Expand Up @@ -93,18 +96,13 @@ android {

sourceSets {
named("foss") {
assets.srcDirs("build/generated/extraRes/foss")
assets.directories.add("build/generated/extraRes/foss")
}
named("store") {
assets.srcDirs("build/generated/extraRes/store")
assets.directories.add("build/generated/extraRes/store")
}
}

applicationVariants.asSequence()
.flatMap { variant -> variant.outputs.asSequence() }
.mapNotNull { output -> output as? com.android.build.gradle.internal.api.BaseVariantOutputImpl }
.forEach { output -> output.outputFileName = "android-${ApplicationInfo.versionName}.apk" }

val releaseConfig = signingConfigs.create("release_config")
with(releaseConfig) {
storeFile = keystoreProperties?.get("releaseKeystorePath")?.let(::file)
Expand Down Expand Up @@ -140,15 +138,15 @@ android {

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
jvmTarget.set(JvmTarget.JVM_1_8)
}
}
}

// called every time gradle gets executed, takes the native dependencies of
// the natives configuration, and extracts them to the proper libs/ folders
// so they get packed with the APK.
task("copyAndroidNatives") {
tasks.register("copyAndroidNatives") {
doFirst {
val armeabiV7Dir = file("libs/armeabi-v7a/").apply { mkdirs() }
val arm64Dir = file("libs/arm64-v8a/").apply { mkdirs() }
Expand Down Expand Up @@ -274,24 +272,26 @@ androidComponents {
}

dependencies {
useCommonLibs()
useGdxModule()
useLightingBfs()

implementation(Dependencies.LibGDX.gdx)
implementation(Dependencies.LibGDX.Android.backend)

"storeImplementation"(platform(Dependencies.Google.Firebase.bom))
"storeImplementation"(Dependencies.Google.Firebase.crashlytics)
"storeImplementation"(Dependencies.Yandex.mobileads)

natives(Dependencies.LibGDX.Android.Natives.armeabi)
natives(Dependencies.LibGDX.Android.Natives.arm64)
natives(Dependencies.LibGDX.Android.Natives.x86)
natives(Dependencies.LibGDX.Android.Natives.x86_64)

natives(Dependencies.LibGDX.Box2d.Natives.Android.armeabi)
natives(Dependencies.LibGDX.Box2d.Natives.Android.arm64)
natives(Dependencies.LibGDX.Box2d.Natives.Android.x86)
natives(Dependencies.LibGDX.Box2d.Natives.Android.x86_64)
implementation(projects.core.common)
implementation(libs.kermit)
implementation(libs.kotlinx.coroutines.core)
implementation(projects.core.gdx)
implementation(projects.core.gameplay.lightingBfs)

implementation(libs.gdx)
implementation(libs.gdx.backend.android)

"storeImplementation"(platform(libs.firebase.bom))
"storeImplementation"(libs.firebase.crashlytics)
"storeImplementation"(libs.yandex.mobileads)

natives(variantOf(libs.gdx.platform) { classifier("natives-armeabi-v7a") })
natives(variantOf(libs.gdx.platform) { classifier("natives-arm64-v8a") })
natives(variantOf(libs.gdx.platform) { classifier("natives-x86") })
natives(variantOf(libs.gdx.platform) { classifier("natives-x86_64") })

natives(variantOf(libs.gdx.box2d.platform) { classifier("natives-armeabi-v7a") })
natives(variantOf(libs.gdx.box2d.platform) { classifier("natives-arm64-v8a") })
natives(variantOf(libs.gdx.box2d.platform) { classifier("natives-x86") })
natives(variantOf(libs.gdx.box2d.platform) { classifier("natives-x86_64") })
}
17 changes: 17 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
google()
gradlePluginPortal()
}

dependencies {
implementation(libs.kotlin.gradle.plugin)
implementation(libs.ksp.gradle.plugin)
implementation(libs.ktlint.gradle.plugin)
api(libs.license.report.gradle.plugin)
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}
14 changes: 14 additions & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
gradlePluginPortal()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

rootProject.name = "build-logic"
Loading
Loading