This branch is intended for hosting dedicated instances of Violent Bot.
You can run this locally free/m or on a vps for vps hosting cost/m
Join Patreon as a paid supporter and I will send you an invite link for the bot I am running myself.
This is the best option if you are non-technical and simply wish to use Violent Bot.
Production:
Current features include:
- Online List
- Levels List
- Deaths List
- Activity Feed
- Server Save Notifications
- Command Log
The code is organised into focused packages under com.tibiabot rather than a few
god-objects. The top-level entry points stay thin:
BotApp— application state and orchestration (wires the collaborators below).BotListener— a thin JDA event dispatcher; routes each event to a handler.TibiaBot— the per-world Akka stream that polls TibiaData and detects deaths/levels.
Supporting packages:
| Package | Responsibility |
|---|---|
app/ |
Startup wiring — Bootstrap (JDA session) and StreamSupervisor (per-world stream lifecycle). |
commands/ |
Slash-command schemas, CommandRouter, Permissions; commands/handlers/ has one object per command. |
interactions/ |
Button, modal and message (screenshot-upload) interaction handlers. |
discord/ |
DiscordGateway (the JDA read seam) and RateLimitedSender (outbound message queue). |
persistence/ |
Repository ports + ConnectionProvider/SchemaInitializer; JDBC/Postgres impls in persistence/jdbc/. All JDBC access goes through JdbcSupport.withConnection, which releases the connection even when a statement throws, so errors can't leak connections under concurrent load. |
presentation/ |
Pure embed/message builders (deaths, online list, boosted, galthen). |
scheduler/ |
Server-save schedule decisions (window, Rashid location, Drome countdown). |
tracking/ |
Death/level/online dedup state and masslog detection. |
tibiadata/ |
TibiaData v4 API client; response models in tibiadata/response/. |
wiki/ |
Fandom wiki client and HTML parser. |
domain/ |
Core case classes; game-time cycles in domain/time/. |
galthen/, boosted/, admin/ |
Feature services extracted from BotApp. |
Concurrency: one independent Akka stream per world (held by StreamSupervisor),
all sharing a single ActorSystem/dispatcher and HTTP pool. Each world ticks every
60s through a back-pressured mapAsync(1) pipeline with a mapAsyncUnordered(32)
fan-out for per-character lookups, and per-stage Supervision.Resume so a single bad
response never kills the stream. Per-world dedup state is isolated to each stream; the
state shared across worlds (state/StreamState) is read lock-free on @volatile fields
and mutated only through synchronized modify* helpers, so concurrent per-guild updates
never clobber each other.
flowchart TB
subgraph sup ["app/StreamSupervisor — one Akka stream per world"]
WA[world A]
WB[world B]
WN[world N]
end
subgraph pipe ["the pipeline each world runs independently — tick 60s, back-pressured"]
direction LR
T["Source.tick 60s"] --> GWp["getWorld<br/>mapAsync(1)"]
GWp --> GC["getCharacterData<br/>mapAsyncUnordered(32)"]
GC --> SDp["scanForDeaths<br/>mapAsync(1)"]
SDp --> PDp["postToDiscord<br/>mapAsync(1)"]
end
WA --> T
WB --> T
WN --> T
GC -->|HTTP per online character| API{{TibiaData v4 API}}
SDp <-->|"@volatile read · synchronized modify*"| ST[("state/StreamState")]
PDp --> SN["RateLimitedSender<br/>per-world queue"] --> JDA["JDA global rate limiter"] --> D([Discord])
WA -.->|run concurrently on| AS[/"shared ActorSystem dispatcher + akka-http pool"/]
WB -.-> AS
WN -.-> AS
The world streams run concurrently on the shared dispatcher and HTTP pool; the only
points they contend on are StreamState (serialised writes) and the JDA rate limiter
(outbound sends). Startup staggers stream launches by ~5.5s so they don't all poll at once.
This is only used for Boosted boss/creature endpoints currently.
Using a local instance of TibiaData gives you quicker notifications.
- Edit the
.envfile
TIBIADATA_HOST=http://tibiadata-api:8080- Run it on the same docker network so violent bot can access it:
docker run -d -p XXXXXXXX:80:8080 --name tibiadata-api --network violentbot --rm -it ghcr.io/tibiadata/tibiadata-api-go:latest- Go to: https://discord.com/developers/applications and create a New Application.
- Go to the Bot tab and click on Add Bot.
- Click Reset Token & take note of the
Tokenthat is generated.
The bot is configured to point to emojis in my discord server.
You will need to change this to point to your emojis.
- Upload the emojis provided in the discord emojis folder to your discord.
- Open the discord.conf file and edit it.
- Point to
emoji idsto ones that exist on your discord server - the ones you uploaded in step 1.
- Ensure
docker(with the Compose plugin) is installed. - Ensure you can build the bot image — either
sbt+Java JDK 8locally
Config and start the Postgres database first:
-
Create a
.envfile and fill out it out:TOKEN=XXXXXXXXXXXXXXXXXXXXXX POSTGRES_HOST=sqlhost POSTGRES_USER=postgres POSTGRES_PASSWORD=XXXXXXXXXX TIBIADATA_HOST=https://api.tibiadata.com/ REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD=XXXXXXXXXXXX
-
Create the docker volume for the postgres database:
docker volume create --name pgdata
-
Create the docker network for the
postgres databaseandviolent botto communicate over:docker network create violentbot
-
Run the postgres docker image:
docker run --rm -d -t --env-file .env --hostname sqlhost --network=violentbot --name postgres -p 5432:5432 -v pgdata:/var/lib/postgresql postgres
The repository ships a docker-compose.yml that runs the bot together with a
Redis cache.
-
Build the bot image (tags
violent-bot-dedicated:latest):sbt docker:publishLocal
Stage the image with the dockerized build, then `docker build`:⚠️ No local sbt?docker run --rm -u "$(id -u):$(id -g)" -e HOME=/cache \ -v "$HOME/.cache/tibiabot-build:/cache" -v "$PWD:/work" -w /work/tibia-bot \ sbtscala/scala-sbt:eclipse-temurin-8u352-b08_1.8.2_2.13.10 sbt -batch docker:stage docker build -t violent-bot-dedicated:latest tibia-bot/target/docker/stage
-
Start the stack:
docker compose up -d
To run without caching, unset REDIS_HOST= in .env.
The project targets Java 8 and builds with sbt. If you don't have a JDK 8 / sbt toolchain locally, build and test in Docker:
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/cache \
-v "$HOME/.cache/tibiabot-build:/cache" -v "$PWD:/work" -w /work/tibia-bot \
sbtscala/scala-sbt:eclipse-temurin-8u352-b08_1.8.2_2.13.10 sbt -batch test- Tail the bot logs:
docker compose logs -f bot(errors are usually self-explanatory). - See what's running:
docker compose ps. - To visualise the databases, run pgAdmin on the compose network:
docker run -t --name pgadmin -p 82:80 --network violentbot -e 'PGADMIN_DEFAULT_EMAIL=you@example.com' -e 'PGADMIN_DEFAULT_PASSWORD=changeme' -d dpage/pgadmin4