Skip to content

Instantly share code, notes, and snippets.

@Cervator
Created September 7, 2017 20:34
Show Gist options
  • Save Cervator/5543042eeec314c456e8cf5d908d86c6 to your computer and use it in GitHub Desktop.
Save Cervator/5543042eeec314c456e8cf5d908d86c6 to your computer and use it in GitHub Desktop.

This is an overview of the different parts of our primary codebase and will be primarily of interest to developers/modders. See also [[Project Overview]] for a higher level view across more different projects.

Gradle and Groovy

Most of our projects are organized using Gradle, a build automation tool similar to Maven, but using Groovy as its language. This allows for some pretty powerful scripting and customization of a local developer setup while leveraging maven repositories for dependency resolution.

You interact with Gradle using a gradlew wrapper script that downloads and installs the correct project-specific version of Gradle itself. No need to install anything locally yourself. You simply run the command gradlew on any OS in the directory you've cloned the primary Terasology engine repo to and the correct version will be fetched and executed.

Much like the Gradle wrapper as of September 2017 we've introduced a Groovy Wrapper variant groovyw that does the exact same thing but for Groovy and Groovy scripts, using the same Groovy runtime shipped with Gradle. This avoids the extra overhead of the Gradle project tree and some of the build nature specifics not needed in some cases.

As you work on Terasology you might find out that you need source or binaries for other sub-projects, which can be added easily to your existing workspace via Gradle or Groovy utility. Keep reading to learn more.

Note: On Linux and Mac OS you may have to first mark the gradlew file as executable and use ./gradlew instead of plain gradlew (same for groovyw)

For more details on our use of Gradle see Fancy Gradle

Engine

The heart and soul of Terasology. All facades and modules depend on the engine.

The primary repo containing the engine is the first and only thing you need to run the game and allows you to use Gradle and Groovy commands to fetch everything else. Always assume you need to execute gradlew or groovyw from the root directory of this project unless stated otherwise. This is the one repo you need to clone manually:

git clone https://github.com/MovingBlocks/Terasology.git

Along with the engine you get the PC Facade and some basic embedded modules. Everything else lives in independent GitHub repos that can be added to your local workspace as sub-projects. You can edit several at once, commit files across multiple Git roots, and push it all to each affected repo on GitHub in one action.

It also comes with several utility tasks, such as project file generation for IDEA IntelliJ. This is our recommended IDE (with a freebie Ultimate Edition available for contributors) and the customized setup for it is fairly detailed.

You can also use Eclipse, NetBeans, or anything else you like, but you might have to figure out some of the setup details yourself - and if you do please post them in the forum so we can improve the instructions to set up with alternative IDEs :-)

gradlew idea

This creates the IntelliJ files you can then use to open the project. Always open using the .ipr file - do not open using the directory or the Gradle file (you may get that to work in theory, but it misses out on our customizations - goal is to properly support this in engine v2). You never need to create a new project from scratch or import anything. With this task you get:

  • A run configuration called "TerasologyPC" will be created and immediately be available for execution. This run configuration includes memory settings and the "-homedir" parameter that makes game data files save in the install directory rather than the data directory (easier for development)
  • A bunch of additional run configurations like that one for running 2nd or 3rd instance of the game with independent data directories, a headless server, etc
  • Git will be mapped as the VCS of choice - as you add additional source modules they'll have their own "Git Root" and be set up likewise
  • [[Checkstyle]] integration with IntelliJ will be enabled. This allows you to catch style violations that clash with the project conventions. Please check these before committing :D
  • You'll be able to automatically insert the [[Project Header]] (copyright etc) in new files (TODO: More details)
  • Some compiler settings will be tweaked, such as "Make Automatically"
  • [[Annotations]], which are used extensively in the project, will get some special consideration when IntelliJ looks at whether code is used or not

The biggest architectural piece of the engine is our [[Entity System|Entity System Architecture]] which powers just about everything, much more than just creatures (typically considered "movable entities" or "mobs")

Facades

The engine alone is not executable. It needs to run in some sort of context - "facades" (front-ends) supply that by wrapping the engine.

The most basic one is the "PC Facade" which simply runs the game normally as an application on Windows, Linux, or Macs. This facade is bundled with the engine repo and available right out of the box.

Another one exists that is specific to running the game as a headless server with additional administrative options. To be able to work with a separate facade you can fetch it automatically:

gradlew fetchFacadeServer

(Note: the gradlew fetch..., create, and other variants are deprecated and scheduled to be removed in the engine's v2 release - replacements are in pure Groovy using groovyw facade get [name] or groovyw module recurse [name])

Facades are hosted in the MovingBlocks organization on GitHub and have their own custom build scripts.

Rarely should a new facade be needed, one could be made with:

gradlew createFacadeWorldEditor

This would create a "facades/WorldEditor" sub-project initialized with a few template files and its own Git repo

TODO: Swap example to the "Developer Facade" (when we have it) which provides additional developer tools at runtime

Modules

If the heart of Terasology is the engine and the facades make up its different faces then the content modules are the different organs - delicious!

While usually "mods" are user-created modifications to a game our modules are a little more fundamental. Modules are containers for code and assets that can be used by game types, mods or other higher-level concepts. Even the systems and various bits of content in the base game are stored in modules that can be enabled, disabled, or even replaced.

Modules have access to a limited part of the engine through the [[Modding API]]. Each is sandboxed for security. Other than the few embedded engine modules they do not get their own custom build file, instead one is copied in from the Core module that builds all modules equally. If you change that instance of the file you can refresh all generated module build files with:

gradlew refreshModuleGradle

(Note: this also changes the engine's v2 release - modules lose their build files entirely and no longer need to be refreshed at all)

This is also a good time to point out that you can abbreviate task names. "gradlew refresh" works as well.

A module can define a "Gameplay Template" which is similar to a "modpack" or some bigger "mods" even. Several such templates are also supplied in the base game like "Josharias Survival" which is a basic survival setup with a focus on climbing a tech tree with machines

With the primary repo you'll have the bundled Core module (which contains the player object and similar important stuff). Here's an example that fetches the Signalling module:

gradlew fetchModuleSignalling

(Note: the gradlew fetch..., create, and other variants are deprecated and scheduled to be removed in the engine's v2 release - replacements are in pure Groovy using groovyw module get [name1 name2...] or groovyw module recurse [name])

On the next execution of Gradle the new module will be detected and scanned. If it has dependencies on other modules Gradle will attempt to resolve them. In the following example "Signalling" depends on "BlockNetwork":

  • Does the dependency exist as another local source module? If so then use that. Example: "modules/BlockNetwork" source directory fetched before the Signalling module.
  • If not then look for a local binary version present in the modules directory. If you later fetch a source module the binary version will be ignored. Example: "modules/BlockNetwork.jar"
  • If a dependency is still not found go to our [[Artifactory]] instance and look there. If found the binary is copied to the local modules directory to be available at runtime. This will resolve as a local binary next time.

Note: Module versioning exists but is not fully respected everywhere - some places simply assume the very latest version is always desired.

You can also create a brand new module and have it filled in with some template content:

gradlew createModuleMyLittleModule

(Note: Yep also deprecated, same story as the above disclaimers. In this case `groovyw module create MyLittleModule would do the same)

This would create "modules/MyLittleModule" and initialize a new Git repo for it locally. To put it online under the Terasology organization on GitHub ask a regular contributor to create the repository there.

After the next Gradle execution (like "gradlew idea" to regenerate IntelliJ files to know about the new module) you can immediately run the game and see the new module available. It won't do much yet though!

For more on modules see [[Developing Modules]]

Other File Types

Beyond code, we have a few major groups of files

  • Game assets - actual content used by the game. Might be textures, block shapes, models, etc. See the Tutorial on our Asset System for more
  • Protobuf - this is a framework for structured data provided by Google. It is used to store data in a binary format for efficient transfer over network connection and rarely changes
  • Module manifests - the module.txt that describes the module and any dependencies it has. This includes versioning information.

We heavily use JSON throughout our projects to store text data / assets, configuration, meta-data, and so on. Rather than using json as the file extension, each asset uses an extension relevant to what it is:

  • .block = Block definition files. See [[Block Architecture]] for more details. Might be outdated at the moment though :-(
  • .shape = Defines a 3d shape that a block may have. These can be exported from Blender using a [[bundled addon|Block Shapes In Blender]]
  • .prefab = "Prefabricated" object, a recipe for creating entities in our entity system. They can also be used to define static information without generating an entity.
  • .texinfo = Added configuration for how textures should behave.

Common Issues and Other Notes

  • If your command window loses focus while working on something that'll pop up an SSH passphrase prompt it may load in the background and be easy to miss. This can leave you with an incomplete sub-project dir
  • Incomplete or otherwise corrupt nested git directories (modules, facades ..) may cause trouble, such as complaining about "cannot find task 'classes' on [name]". When in doubt: Delete and fetch again
  • Same issue may cause tasks to think you already have a particular module locally - again just delete the partial directory and try again
  • You may also get a password prompt if you made a typo in a module name (GitHub is trying to see if you have access to a private repo by that name, thus asking for you to authenticate with your user to find out)
  • You cannot add the "idea" task to the same execution of Gradle as a task that messes with the project structure. "gradlew createModuleTestExecutionOrder idea" will not correctly apply the IntelliJ generation step to the brand new TestExecutionOrder module. Same goes for other tasks that base off the project structure - mess with the structure in one step then apply it in another
  • If you get compile errors on trying to run with the provided configuration immediately after setting up IntelliJ try doing a full Project Rebuild (may be a poor dependency order compilation issue - or IntelliJ just hasn't finished its initial background build) or attempt gradlew jar

Related Pages

  • [[Dev Setup]]
  • [[Modding Guide]]
  • [[Modding API]]
  • [[Entity System Architecture]]
  • [[Shape Architecture]]
  • [[Checkstyle]]
  • [[Unit Testing]]
  • [[JavaDoc]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment