A Discord bot for Egg, Inc. co-op communities.
To facilitate teamwork for Egg, Inc. communities this bot creates team rosters out of all registered players for any given active contract, allows checking up on the progress of all teams or a detailed view of an individual team and enables setting goals for individual players. This bot is being used daily by a private community of over 70 people.
It is able to predict whether a team will reach their contract goals by running a simulation on each of the member's latest known game state, taking into account all relevant variables from current amount of chickens and performed research to the time since last backup and the transport and habitat capacity.
- Install the dependencies listed below
- Use the supplied
eggbot.example.yaml
andexample.env
in the folder you're running the bot from. - Test using e.g.
./gradleW run
- Java Runtime Environment 11
- PostgreSQL
A few technically interesting features are highlighted here:
- Model View Controller structuring
- Multithreaded/asynchronous processing of heavy workloads
- Leverage of Java interoperability to combine Java and Kotlin libraries and frameworks
- Multi-tenancy using directory based database sharding
- Deployed on a self-managed VPS
- Development, testing, acceptance and production (DTAP)
The simulation calculates each passing minute until either the final goal will be reached within the time limit or one year has passed.
The calculation is performed recursively and stateless; all relevant information is passed in the form of data classes, increasing reliability and separating concerns.
Co-op states use Kotlin's sealed classes in order to simplify the view (i.e. table
formatting) while still accounting for all possible states by leveraging Kotlin's ability to use that specific sealed class object’s variables as determined by the when
case.
In order to produce consistently formatted tables that can be easily iterated upon a custom DSL was made. The DSL enables concise, readable and flexible HTML-like code for generating tables.
Since fetching the backup for each player can take a while even when performed asynchronously, a progress bar is drawn to indicate progress of the parallel fetching and simulating of player's farm state. The progress bar runs a loop that only edits the message once per second and only when a change has occurred.
Kotlin offers an incredible flexibility by allowing extension methods for any class. This project uses many of these ‘helper methods’, ordered by which dependency they augment.
As an example: to aid a functional programming style when handling data these methods add the ability to map over cartesian products ([a, b, c], [1, 2, 3]
→ [a1, b1, c1, a2, b2…]
), interleaving lists ([a, b, c], [1, 2, 3]
→ [a, 1, b, 2, c, 3]
) and mapping over collections asynchronously.