A modular Java bot for the F-List chat WebSocket API with a clean separation between:
- Transport layer (WebSocket connection, queues, reconnect logic)
- Application layer (command handling, persistence, bot behavior)
This README gives a developer everything needed to run, understand, and extend the bot.
The project is structured around three main components:
Main → BotTransport → BotApplication
↘
FListWebSocketClient
Bootstraps the application and transport.
- Loads account settings
- Starts the bot application
- Starts the transport layer
- Keeps JVM alive
Handles all networking and runtime orchestration.
Responsibilities:
- WebSocket connection lifecycle
- Reconnect logic
- Message queues (inbound/outbound)
- Message pump
- Watchdog monitoring
- Sending outbound messages
Does not contain bot logic.
Contains all bot logic and persistence.
Responsibilities:
- Command parsing (
!help,!ping, etc.) - Saving / backup
- Autosave timer
- Data storage
Does not know about WebSockets.
Low-level WebSocket adapter.
Responsibilities:
- Connect to F-List WebSocket
- Send raw protocol frames
- Parse incoming frames into
Message - Notify
BotTransport
No command logic here.
|| InQueue || ||Processing|| || OutQueue ||
WebSocket → BotTransport → BotApplication → BotTransport → WebSocket
- Server sends
MSGorPRIdepending on message type - WebSocket client parses →
Message - Transport enqueues inbound
- Pump calls
BotApplication.handle() - BotApplication returns response message
- Transport enqueues outbound
- Transport sends frame to server
- Java 17+
- Gradle 7.3+ (wrapper included)
Dependencies:
- OkHttp (WebSocket)
- org.json
- SLF4J + Logback
Create file:
LocalVariables/accountSettings.txt
Format:
AccountName:yourAccount;
AccountPassword:yourPassword;
CharacterName:Your Character;
CName:Your Character;
Channel:adh-xxxxxxxxxxxxxxxx
From project root:
./gradlew runMainor Windows:
.\gradlew.bat runMainDefault prefix: !
Example Commands Implemented
| Command | Description |
|---|---|
!help |
Show command list |
!ping |
Test response |
!save |
Save character data |
!backup |
Create backup |
Add commands in BotApplication.handleCommand().
In BotApplication:
case "roll" -> {
incoming.setOutputMessage("You rolled a 4");
return incoming;
}Return multiple messages or queue them manually in BotTransport.
In BotTransport.onIncomingMessage():
if (message.characterName.equalsIgnoreCase(settings.characterName())) {
return;
}Prevents bot responding to its own messages.
The bot uses F-List API ticket authentication.
Tickets are cached and refreshed automatically.
If you see:
Login Failed. Too many failed attempts. Requests throttled.
Wait before retrying. The bot will back off automatically.
Logs are printed to console with timestamps.
Adjust logging in BotApplication.log() or configure Logback.
Check:
- Prefix is correct
- Bot joined correct channel
- MessageQueue is thread-safe
handle()returns a message
Check:
- Channel ID correct
- Character logged in
- Server echo disabled
- Watchdog logs
Check:
- Credentials
- Throttling
- Network connectivity
- All networking is isolated in
BotTransport - All logic belongs in
BotApplication - Never put bot logic in WebSocket client
- Never put network logic in BotApplication
org.example
├─ Main.java
└─ Websocket
├─ BotApplication.java
├─ BotTransport.java
├─ FListWebSocketClient.java
├─ FListAuthService.java
├─ Message.java
└─ MessageQueue.java
When modifying code:
- Keep transport and application separate
- Add logs for new flows
- Test commands locally
- Avoid blocking inside
handle()
Internal / personal use unless otherwise specified.