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
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions AGENTS.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid placing this file in the root directory of the project somehow? Given the lack of human focus, it makes sense to put it somewhere where humans would not immediately look.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, thinking maybe /config since it is essentially config for AI

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Agent Workflow & Lessons Learned

This document serves as a living guide for AI agents working on the Terasology project. It captures workflow best practices, platform-specific quirks, and useful commands to ensure efficient collaboration.

## Platform: Windows & PowerShell

General coding on Linux and Mac are well-understood by AI, while Java on Windows with PowerShell is less so, meaning we need extra tips and options here.

- **Path Separators**: Use forward slashes `/` for Gradle tasks and Java paths where possible, but be aware that Windows system paths use backslashes `\`.
- **Command Syntax**: PowerShell handles quotes and environment variables differently than Bash.
- *Env Vars*: `$env:VAR="value"; command`
- *Chaining*: Use `;` instead of `&&` if you want unconditional execution, or `if ($?) { command }` for conditional.
- **File Search**: To find files recursively:
```powershell
Get-ChildItem -Path . -Filter filename.txt -Recurse
```
- **Environment Setup**:
- **JAVA_HOME**: PowerShell terminals in the IDE may not inherit system variables correctly. Set it explicitly for the session plus update the PATH:
```powershell
$env:JAVA_HOME = "D:\Dev\Java\TemurinJDK17"
$env:Path = "$env:JAVA_HOME\bin;$env:Path"
```
- **Path**: You can verify java is accessible with `& "$env:JAVA_HOME\bin\java" -version`.
## Search and Navigation
* **Use Search Tools**: When looking for specific method calls, variable usages, or class definitions across the codebase, try to use `grep_search` or `codebase_search` instead of manually traversing files one by one. This is faster and more exhaustive.
* **Scoped Search**: Narrow down search scope using `TargetDirectories` or `SearchPath` to reduce noise.
## Gradle & Build System
- **Verbosity**: Gradle output can be overwhelming.
- Avoid `--info` or `--debug` unless necessary.
- If output is truncated, check XML reports: `build/test-results/test/TEST-*.xml`.
- **Running Tests**:
- Use specific filters: `./gradlew :project:test --tests "package.ClassName"`
- Example: `./gradlew :engine-tests:test --tests "org.terasology.engine.BuildValidationTest"`
- **Task Execution**:
- **Force Run**: To force a test to run without rebuilding the whole project, use `cleanTest` before the test task:
` ./gradlew :engine-tests:cleanTest :engine-tests:test --tests "org.terasology.metatesting.MTETwoClientChatTest"`
- **Nuclear Option**: `--rerun-tasks` will rerun EVERYTHING. Use sparingly.
- **Clean Builds**: When in doubt (class not found, weird linkage errors), run `./gradlew clean`.
## Context Management
- **Logs**: Do not dump full log files into the chat context.
- Use `grep` (or `Select-String` in PS) to find relevant lines.
- Read specific blocks of XML reports.
- **File Viewing**: Use `view_file` with line ranges to inspect relevant code sections.
- **Debugging**: When tests fail or timeout, use `System.out.println` *before* assertions or inside `runUntil` loops to dump relevant state (e.g., object counts, flags, current states). This is often faster than attaching a debugger.
## Testing Strategy: "Meta-Test Suite"
We are building a validation suite from the ground up to verify the test infrastructure itself.
1. **Build & Classpath**: Verify resources can be loaded.
2. **Module Loading**: Verify `ModuleManager` works.
3. **DI & Registry**: Verify injection and `CoreRegistry`.
4. **Entity System**: Verify `EntityManager` and Events.
5. **MTE/Multiplayer**: Verify full game environment.
## Common Issues
- **Context Pollution**: `CoreRegistry` is a deprecated static singleton meant to be removed. Tests running in the same JVM must be careful about cleaning it up or isolating contexts.
- **Module Permissions**: The `SecurityManager` (via `ModuleSecurityManager`) can block access to classes. Ensure modules have correct dependencies and permissions.
- **Service vs System**: Distinguish between `Context`/`CoreRegistry` services (global, available via `@In`) and ECS Systems (event-driven, registered with `ComponentSystemManager`). Some functionality (like Chat) relies on ECS systems processing events, not just the service being present.
## Conventions
* Max line length in code files is 150 characters
* Do not make linting or whitespace-only changes to files unless explicitly requested
* If edits repeatedly result in corrupted files (large deleted chunks) start solely rewriting the file from scratch
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Documentation and planning files committed to repository

Several files containing AI agent instructions (AGENTS.md), future task roadmaps (future_tasks.md), and testing plans (testing_plan.md) were added. These appear to be working documents and personal notes from the development session rather than permanent project documentation. The PR reviewer specifically flagged not to commit AI-generated intermediate files.

Additional Locations (2)

Fix in Cursor Fix in Web

18 changes: 18 additions & 0 deletions config/gradle/common.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,21 @@ tasks.javadoc {
// TODO: Temporary until javadoc has been fixed for Java 8 everywhere
failOnError = false
}

apply plugin: 'jacoco'

jacoco {
toolVersion = "0.8.13"
}

test {
finalizedBy jacocoTestReport
}

jacocoTestReport {
dependsOn test
reports {
xml.required = true
html.required = true
}
}
Comment on lines +46 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we need to add this here? If my understanding is correct, this will force jacoco reports to be generated for all tests in modules that inherit their configuration from common.gradle. I thought that was an expensive operation before but things may have moved on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If memory serves the biggest problem with JaCoCo was flooding Jenkins with heavy build reports, causing it to run out of space repeatedly. I'm cautious about re-including it and doubly so how to configure it, for the moment it is largely a local experiment to better figure out where to focus on tests. I was tempted to leave it local-only for the moment but since this branch will get a major cleanup anyway maybe I can test it in Jenkins a bit more this way :-)

20 changes: 20 additions & 0 deletions engine-tests/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ tasks.named<Test>("test") {
description = "Runs all tests (slow)"
useJUnitPlatform ()
systemProperty("junit.jupiter.execution.timeout.default", "4m")
testLogging {
events("passed", "skipped", "failed")
showStandardStreams = true
}
}

tasks.register<Test>("unitTest") {
Expand Down Expand Up @@ -160,3 +164,19 @@ idea {
isDownloadSources = true
}
}

tasks.named<org.gradle.testing.jacoco.tasks.JacocoReport>("jacocoTestReport") {
// Cross-module support: The tests in this module (:engine-tests) exercise code located in the :engine module.
// By default, JaCoCo only looks at sources in the current project. We must explicitly add the :engine
// main source set and output classes so that the coverage report includes the actual engine code.
val engineProject = project(":engine")
val sourceSets = engineProject.extensions.getByType(SourceSetContainer::class)
val mainSourceSet = sourceSets.getByName("main")

additionalSourceDirs.from(mainSourceSet.allSource)
additionalClassDirs.from(mainSourceSet.output)
reports {
xml.required.set(true)
html.required.set(true)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are PMD and CheckStyle warnings in this file reported by Jenkins that I quite agree with. It would be worth fixing those.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.terasology.metatesting;

Check warning on line 1 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / CheckStyle

RegexpHeaderCheck

NORMAL: Line does not match expected header line of '// Copyright 20\d\d The Terasology Foundation'.
Raw output
<p>Since Checkstyle 6.9</p><p> Checks the header of a source file against a header that contains a <a href="https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html">regular expression</a> for each line of the source header. </p><p> Rationale: In some projects <a href="#Header">checking against a fixed header</a> is not sufficient, e.g. the header might require a copyright line where the year information is not static. </p><p> For example, consider the following header: </p><pre><code> line 1: ^/{71}$ line 2: ^// checkstyle:$ line 3: ^// Checks Java source code for adherence to a set of rules\.$ line 4: ^// Copyright \(C\) \d\d\d\d Oliver Burn$ line 5: ^// Last modification by \$Author.*\$$ line 6: ^/{71}$ line 7: line 8: ^package line 9: line 10: ^import line 11: line 12: ^/\*\* line 13: ^ \*([^/]|$) line 14: ^ \*/ </code></pre><p> Lines 1 and 6 demonstrate a more compact notation for 71 '/' characters. Line 4 enforces that the copyright notice includes a four digit year. Line 5 is an example how to enforce revision control keywords in a file header. Lines 12-14 is a template for javadoc (line 13 is so complicated to remove conflict with and of javadoc comment). Lines 7, 9 and 11 will be treated as '^$' and will forcefully expect the line to be empty. </p><p> Different programming languages have different comment syntax rules, but all of them start a comment with a non-word character. Hence you can often use the non-word character class to abstract away the concrete comment syntax and allow checking the header for different languages with a single header definition. For example, consider the following header specification (note that this is not the full Apache license header): </p><pre><code> line 1: ^#! line 2: ^&lt;\?xml.*&gt;$ line 3: ^\W*$ line 4: ^\W*Copyright 2006 The Apache Software Foundation or its licensors, as applicable\.$ line 5: ^\W*Licensed under the Apache License, Version 2\.0 \(the "License"\);$ line 6: ^\W*$ </code></pre><p> Lines 1 and 2 leave room for technical header lines, e.g. the "#!/bin/sh" line in Unix shell scripts, or the XML file header of XML files. Set the multiline property to "1, 2" so these lines can be ignored for file types where they do no apply. Lines 3 through 6 define the actual header content. Note how lines 2, 4 and 5 use escapes for characters that have special regexp semantics. </p>

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.net.URL;
import java.util.Enumeration;

public class BuildValidationTest {

@Test
public void testClasspathSanity() {
System.out.println("Running BuildValidationTest: Checking classpath sanity...");

Check warning on line 13 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>

// 1. Check if we can load a standard Java class
assertNotNull(String.class, "Should be able to load String class");

// 2. Check if we can find the TerasologyEngine class
URL resource = getClass().getResource("/org/terasology/engine/core/TerasologyEngine.class");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not really like the idea of hard-coding paths to arbitrary class files here, even if it is just for a unit test. It makes the test fail if we ever re-name the class or change its package. Could we construct the class file path by using TerasologyEngine.class.<something> instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably! I did notice this as odd vs easier and more generic things to test, but then that's the messy first pass largely from the one-handed-button-mashing-with-kids approach 👍


if (resource == null) {
System.out.println("FATAL: TerasologyEngine class not found!");

Check warning on line 22 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
System.out.println("Current ClassLoader: " + getClass().getClassLoader());

Check warning on line 23 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
System.out.println("Java Classpath: " + System.getProperty("java.class.path"));

Check warning on line 24 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
} else {
System.out.println("Classpath sanity check passed. Found TerasologyEngine at: " + resource);

Check warning on line 26 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
}

assertNotNull(resource, "Should be able to find TerasologyEngine class resource");

// 3. Check for module.txt
// We found it at org/terasology/engine/module.txt in the source
URL moduleTxt = getClass().getResource("/org/terasology/engine/module.txt");

if (moduleTxt == null) {
System.out.println("WARNING: /org/terasology/engine/module.txt not found. Checking for any module.txt...");

Check warning on line 36 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
try {
Enumeration<URL> resources = getClass().getClassLoader().getResources("module.txt");
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
System.out.println("Found a module.txt at: " + url);

Check warning on line 41 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
if (url.toString().contains("engine")) {
moduleTxt = url;
}
}
} catch (Exception e) {
e.printStackTrace();

Check warning on line 47 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

AvoidPrintStackTrace

NORMAL: Avoid printStackTrace(); use a logger call instead.
Raw output
Avoid printStackTrace(); use a logger call instead. <pre> <code> class Foo { void bar() { try { // do something } catch (Exception e) { e.printStackTrace(); } } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#avoidprintstacktrace"> See PMD documentation. </a>
}
} else {
System.out.println("Found engine module.txt at: " + moduleTxt);

Check warning on line 50 in engine-tests/src/test/java/org/terasology/metatesting/BuildValidationTest.java

View check run for this annotation

Terasology Jenkins.io / PMD

SystemPrintln

HIGH: Usage of System.out/err.
Raw output
References to System.(out|err).print are usually intended for debugging purposes and can remain in the codebase even in production code. By using a logger one can enable/disable this behaviour at will (and by priority) and avoid clogging the Standard out log. <pre> <code> class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println(&quot;Entering test&quot;); // Better use this log.fine(&quot;Entering test&quot;); } } </code> </pre> <a href="https://docs.pmd-code.org/pmd-doc-7.7.0/pmd_rules_java_bestpractices.html#systemprintln"> See PMD documentation. </a>
}

assertNotNull(moduleTxt, "Should be able to find module.txt for the engine module");
}
}
Loading
Loading