diff --git a/.gitignore b/.gitignore index 8114c1e13ee..a37e0334697 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,13 @@ blacklist.json terasology.jfr local.properties *.hprof + +### BROKK'S CONFIGURATION ### +.brokk/** +/.brokk/workspace.properties +/.brokk/sessions/ +/.brokk/dependencies/ +/.brokk/history.zip +!AGENTS.md +!.brokk/style.md +!.brokk/project.properties diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..e7442d46e86 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,52 @@ +# Terasology Coding Style Guide + +This guide captures the specific coding patterns and Gradle conventions found in the Terasology codebase, focusing on modern Gradle Kotlin DSL (KTS) usage and engine-specific architectures. + +## 1. Build System & Gradle (KTS) + +The project uses Gradle Kotlin DSL with a centralized `build-logic` composite build. + +### Dependency Management +- **Version Catalogs**: Use the `libs` catalog in `settings.gradle.kts` for common dependencies. +- **Constraints**: Use `constraints { ... }` blocks to force specific transitive dependency versions (e.g., forcing a newer `bytebuddy` for Java 17 compatibility). +- **Dependency Substitution**: Use `resolutionStrategy.dependencySubstitution` to swap remote module dependencies with local project sources when available. +- **Platform BOMs**: Use `platform()` for grouping related dependencies (e.g., LWJGL). + +### Task Configuration +- **Lazy Registration**: Favor `tasks.register("name")` over `tasks.create`. +- **Property Delegation**: Use `val propertyName by extra("value")` for sharing variables across subprojects. +- **Inputs/Outputs**: Always define `outputs.dir` or `outputs.file` for custom extraction/copy tasks to support Gradle's up-to-date checks and automatic `clean` task generation. +- **Duplication Strategy**: Explicitly set `duplicatesStrategy = DuplicatesStrategy.EXCLUDE` when merging resources or classes from multiple source sets. + +### Java Toolchains & Compatibility +- **JVM Toolchain**: Strictly target Java 17 using `jvmToolchain(17)`. +- **Validation**: Include runtime checks in build scripts to warn users if the `JavaVersion.current()` deviates from the expected version. + +## 2. Java & Engine Architecture + +### Dependency Injection & Context +- **The `@In` Annotation**: Use the `@In` annotation for automatic service injection within NUI screens and engine components. +- **Context Registry**: Use `context.get(Class)` to retrieve engine services and `CoreRegistry.put()` for global accessibility when necessary. + +### Resource & Asset Handling +- **ResourceUrn**: Always use `ResourceUrn` for identifying assets (e.g., `engine:universeSetupScreen`). +- **Asset Templates**: Store static configuration templates in the `/templates` directory and use custom tasks like `CopyButNeverOverwrite` to initialize them into the project root. + +### UI Development (NUI) +- **Binding Pattern**: Use `Binding` and `ReadOnlyBinding` to link UI widgets (like `UIText` or `UIDropdown`) to underlying configuration data. +- **Widget Subscription**: Use `WidgetUtil.trySubscribe(this, "widgetId", handler)` for cleaner event handling. +- **Wait Popups**: Long-running operations (like world preview generation) must be wrapped in a `WaitPopup` using `Callable` operations to keep the UI responsive. + +## 3. Automation & CI (Jenkins) + +- **Declarative Pipelines**: Use Jenkins Declarative Pipeline syntax with `post { always { ... } }` for test result aggregation. +- **Static Analysis Integration**: Build stages should explicitly trigger `recordIssues` for Checkstyle, PMD, and SpotBugs. +- **Flaky Test Management**: Segregate tests using JUnit 5 tags: + - `unitTest`: Fast, excludes `MteTest`/`TteTest`. + - `integrationTest`: Slow, includes `MteTest`/`TteTest`, excludes `flaky`. + - `integrationTestFlaky`: Only runs tests tagged with both integration tags and `flaky`. + +## 4. Metadata & Versioning + +- **Module Metadata**: Engine and module versions should be mastered in `module.txt` (JSON format) and read into the build system via `JsonSlurper`. +- **Version Info**: The build must generate a `versionInfo.properties` file containing Git hashes, build numbers, and timestamps to be bundled within the JAR for runtime diagnostics. \ No newline at end of file diff --git a/facades/PC/src/main/java/org/terasology/engine/Terasology.java b/facades/PC/src/main/java/org/terasology/engine/Terasology.java index 215862b7290..0ef4c8b401d 100644 --- a/facades/PC/src/main/java/org/terasology/engine/Terasology.java +++ b/facades/PC/src/main/java/org/terasology/engine/Terasology.java @@ -140,8 +140,18 @@ public static void main(String[] args) { @Override public Integer call() throws IOException { + // IMPORTANT: Logging must be initialized BEFORE any class with a static Logger field + // is loaded. Classes like PathManager have static loggers that trigger Logback + // initialization when the class is loaded. If Logback initializes before + // LoggingContext.initialize() sets the logFileFolder system property, + // it creates a "logFileFolder_IS_UNDEFINED" directory. + // + // Therefore: compute log path directly from homeDir, then call setupLogging(), + // THEN call handleLaunchArguments() which loads PathManager. + Path logPath = (homeDir != null ? homeDir : Paths.get(".")).resolve("logs"); + setupLogging(logPath); + handleLaunchArguments(); - setupLogging(); SplashScreen splashScreen; if (splashEnabled) { @@ -257,13 +267,8 @@ private static String getNewTitle(String title) { return (newTitle + " " + fileNumber); } - private static void setupLogging() { - Path path = PathManager.getInstance().getLogPath(); - if (path == null) { - path = Paths.get("logs"); - } - - LoggingContext.initialize(path); + private static void setupLogging(Path logPath) { + LoggingContext.initialize(logPath); } private void handleLaunchArguments() throws IOException { @@ -275,7 +280,9 @@ private void handleLaunchArguments() throws IOException { } if (homeDir != null) { - logger.info("homeDir is {}", homeDir); + // Use stdout here since this is pre-initialization diagnostic output. + // Logger is available but using println keeps the initialization sequence clear. + System.out.println("homeDir is " + homeDir); PathManager.getInstance().useOverrideHomePath(homeDir); // TODO: what is this? // PathManager.getInstance().chooseHomePathManually();