You will need a recent version of [JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html).
Old JDK versions do have bugs that will prevent the code from compiling.
You will also need [Maven](http://maven.apache.org).
To build everything, just run `mvn clean package`.
This should download all dependencies from our [repository](https://repo.extension.ws) and create several .jar files in the `target` directories of each module.
If the build fails, please report it in Discord.
You can also download builds from our [Jenkins](https://build.extension.ws) server.
* We make good use of SportBukkit's built-in Guice support:
* Each plugin has its own [private environment](https://github.com/OvercastNetwork/minecraft-api/blob/master/src/main/java/tc/oc/inject/ProtectedModule.java)
* Each plugin instance is bound to `org.bukkit.plugin.Plugin` inside its private module.
* Anything that indirectly depends on `Plugin` will need to be bound in some plugin's private module.
* If other plugins need access to that thing, it needs to be [exposed](https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/PrivateModule.html#expose-com.google.inject.Key-).
* Avoid depending on `Plugin` directly. There are specific bindings for most Bukkit service types (e.g. `Configuration`)
and several interfaces of our own that wrap small parts of the Bukkit API (e.g. `BukkitEventBus`).
* If you really need a `Plugin`, always inject the base interface, never a specific plugin's class. This makes it easy to move things between plugins.
* Detect errors as early as possible, ideally at server startup. This applies to both user errors and internal assertions.
* Only catch specific exceptions that you are expecting and can handle thoroughly. Don't hide exceptions that other handlers need to know about.
* Avoid catching common exceptions like `IllegalArgumentException`, because it's hard to be certain where they come from.
If you need to catch them, keep the code inside the `try` block as small as possible.
* Don't catch all exceptions or try to handle internal errors for no particular reason. We have a nice framework for dealing with unhandled exceptions at the top-level.
* If you need to implement a general exception handler, inject a `tc.oc.commons.core.exception.ExceptionHandler` and pass it the exceptions.
* Ensure that all errors are seen by a human who knows how to fix them:
* Pure user errors only need to be sent to the user who provided the bad input
* Map errors can be sent to builders in-game (and in Sentry too, on production servers) using the `MapdevLogger`.
* Any unexpected exception on any server must notify developers somehow i.e. through the `LoggingExceptionHandler` or some system logger.
You can tell the user about the error so they know what's going on, but don't expect them to deal with it.
* Concurrency
* Avoid concurrency. It's hard, and we don't have a general solution for doing it safely.
* A Bukkit server has a single "main thread" where most game logic runs, and multiple background threads for I/O and serialization.
All `Event`s (except `AsyncEvent`s) and scheduled tasks (except async tasks) run on the main thread.
* Our own plugins use background thread pools for API operations, which use HTTP and AMQP.
* Never block the main thread on API calls, or any other I/O operation. Use `ListenableFuture`s and `FutureCallback`s to handle API results.
* Don't use the Bukkit API, or any of our own APIs, from a background thread, unless it is explicitly allowed by the API.
Use `MainThreadExecutor` or `SyncExecutor` to get back on the main thread from a background thread.
* A Bungee server is entirely multi-threaded. Handlers for a specific event run in sequence, but seperate events and tasks can run concurrently.
This is one of the reasons we avoid doing things in Bungee.
* Localization
* All in-game text must be localized.
* To add a text string to the game, put the english template in one of the `.properties` files in Commons.
* Use a `TranslatableComponent` to display the localized message. However, it must pass through the `ComponentRenderContext` before being
sent to the player. That will apply the server-side translations.
* Any changes to the templates must be sent to Crowdin before volunteers can start translating them.
This is done with the [Crowdin integration tool](https://crowdin.com/page/cli-tool) by running `crowdin-cli upload sources` in the Commons folder.
This should be done after the new code is deployed to production.
* Libraries
* TODO
* Utilities
* TODO
* Testing
* TODO
* Logging
* TODO
## Workflow
* We use Git, with a typical [feature branch workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow)
* Trivial changes and emergency fixes can be merged straight to the master branch
* Any significant change requires a PR, and code review by at least one other developer.
This applies indiscriminately to all developers. Everyone should have their code reviewed, and anyone can review anyone else's code.
* Once a change has been merged to master, it should be deployed ASAP so that problems can be found.
Deploying several old changes at once just makes it harder to trace bugs to their source.
* Without automated tests, we rely heavily on user reports and Sentry alerts to discover regressions.
Developers should be around for at least a few hours after their change is deployed, in case something breaks.