Streamer.bot v1.0.4 · SQLite WAL · OBS Browser Source
| Requirement | Notes |
|---|---|
| Streamer.bot v1.0.4 | Download from streamer.bot |
| SQLite for .NET | System.Data.SQLite — already bundled with SB |
| Newtonsoft.Json | Already bundled with SB |
| OBS Studio | Browser Source support |
| DB Browser for SQLite | (optional) for manual inspection |
C:\StreamerBot\
│
├── Data\
│ ├── economy.db ← created automatically by schema script
│ ├── Logs\ ← log files written here daily
│ └── icons\ ← your SVG rank icons (see step 3)
│
└── Overlay\
└── Overlay.html ← copy from deliverable
Create the folders manually or run in PowerShell:
New-Item -ItemType Directory -Force "C:\StreamerBot\Data\Logs"
New-Item -ItemType Directory -Force "C:\StreamerBot\Data\icons"
New-Item -ItemType Directory -Force "C:\StreamerBot\Overlay"- Download DB Browser for SQLite (free): https://sqlitebrowser.org/
- Open it → New Database → save as
C:\StreamerBot\Data\economy.db - Click Execute SQL tab
- Paste the entire contents of
schema.sql - Click ▶ Run
- You should see:
Query executed successfullywith no errors - File → Write Changes then close DB Browser
The
PRAGMA journal_mode=WAL;line is the first thing executed — this is what enables the Minecraft plugin to read simultaneously without locking.
Copy your SVG files into C:\StreamerBot\Data\icons\ with exactly these filenames (all lowercase):
wood.svg
bronze.svg
silver.svg
gold.svg
platinum.svg
emerald.svg
diamond.svg
master.svg
grandmaster.svg
eternal.svg
The overlay loads them via the rankIcon field in the WebSocket payload (e.g. /icons/wood.svg). Since OBS Browser Source runs locally, you must configure the Local File base path in OBS (see step 7).
- Open Streamer.bot
- Go to Servers/Clients → WebSocket Server
- Check "Enabled"
- Set Port to
8080(or match what's inOverlay.html→WS_URL) - Leave Endpoint as
/ - Click Save
For each action below, go to Actions tab → + (Add Action) → name it → add a Sub-Action of type "Execute C# Code".
Inside the code editor, paste:
- The entire Shared Helpers block (everything above
ACTION 1) - Then only the
CPHInlineclass for that specific action (uncomment the block you need)
| # | Action Name | Trigger | Which CPHInline block |
|---|---|---|---|
| 1 | Economy - Watch Time |
Timer (60s) | ACTION 1 — Watch Time |
| 2 | Economy - Open Bet |
Command !openbet (Broadcaster only) |
ACTION 2 — Open Bet |
| 3 | Economy - Place Bet |
Command !bet (Everyone) |
ACTION 3 — Place Bet |
| 4 | Economy - Lock Bet |
Command !lockbet (Broadcaster only) |
ACTION 4 — Lock Bet |
| 5 | Economy - Resolve Bet |
Command !resolvebet (Broadcaster only) |
ACTION 5 — Resolve Bet |
| 6 | Economy - Annuncio |
Command !annuncio (Everyone) |
ACTION 6 — Annuncio |
| 7 | Economy - Chat Payload |
Event: Chat Message | ACTION 7 — Chat Payload |
| 8 | Economy - Eternal Check |
Timer (15 min) | ACTION 8 — Eternal Check |
| 9 | Economy - Season Reset |
Command !seasonreset (Broadcaster only) |
ACTION 9 — Season Reset |
| 10 | Economy - Balance |
Command !balance / !points (Everyone) |
ACTION 10 — Balance |
- Go to Timers tab → +
- Name it
Watch Time Timer - Set interval to 60 seconds
- Assign action:
Economy - Watch Time - Enable "Fire on Start": No (to avoid firing while stream is offline)
Same as above but interval = 900 seconds, action = Economy - Eternal Check.
- Open action
Economy - Chat Payload - In the Triggers panel → + → Twitch → Chat Message
- Leave it as Any message (no filter)
- This fires for every single chat message and pushes the overlay payload
For each command action:
- Go to Commands tab → +
- Set the Command field to e.g.
!bet - Set Action to the corresponding economy action
- For broadcaster-only commands: set Permission → Broadcaster
- For everyone: set Permission → Everyone
| Command | input0 |
input1 |
rawInput |
|---|---|---|---|
!openbet <title> | <a> | <b> |
— | — | full text after command |
!bet <a|b> <amount> |
a or b |
amount | — |
!resolvebet <a|b> |
a or b |
— | — |
!annuncio <message> |
— | — | full text after command |
In Streamer.bot v1.0.4, %rawInput% is the full message after the command trigger. %input0% and %input1% are space-split tokens. These are automatically available in args via CPH.TryGetArg().
After pasting code into the editor:
- Click "Compile" — it must say
Compiled Successfullywith zero errors - Click "Execute" once to test (or trigger the chat command in your test channel)
- Check
C:\StreamerBot\Data\Logs\economy_YYYYMMDD.logfor output
- Copy
Overlay.htmltoC:\StreamerBot\Overlay\Overlay.html - In OBS: Sources → + → Browser
- Check "Local File"
- Browse to
C:\StreamerBot\Overlay\Overlay.html - Set Width: 1920, Height: 1080
- Check "Refresh browser when scene becomes active"
- Under Custom CSS: leave blank (styles are already inline)
Important: Because OBS Browser Source uses a local file path, the
/icons/wood.svgURL in the payload won't resolve automatically. Two options:
- Option A (recommended): Place
Overlay.htmldirectly insideC:\StreamerBot\Data\and seticons\as a sibling folder. Use a relative path in the JS: changerankIconconstruction inEconomyConfigfrom/icons/toicons/.- Option B: Use
http://localhost/with a tiny local HTTP server (Python:python -m http.server 8081 --directory C:\StreamerBot\Data), and set icon paths ashttp://localhost:8081/icons/wood.svg.
- Start Streamer.bot + connect to Twitch
- Open OBS with the Browser Source visible
- Type any message in your Twitch chat
- The overlay should show the message with rank icon and glow
- Check the log file — you should see
[INFO] [ChatPayload]entries - Run
!balancein chat — bot should reply with your points
All tunable values are in EconomyConfig (at the top of EconomySystem.cs):
| Constant | What it controls |
|---|---|
WATCH_TIME_POINTS |
Points per minute of watch time (default: 1) |
ANNUNCIO_COST |
Points cost of !annuncio (default: 150) |
BET_PAYOUT_MULT |
Winner payout multiplier (default: 2 = 2×) |
ETERNAL_MIN_PTS |
Minimum seasonal points to qualify for Eternal (default: 35,000) |
ETERNAL_TOP_N |
How many top positions get Eternal (default: 3) |
RankThresholds[] |
Array of point thresholds per rank (index 0–8) |
MaxBets[] |
Max bet amount per rank (index-aligned with ranks) |
RankColors[] |
Hex colour used for glow and icons |
DB_PATH |
Change if you move the database file |
LOG_DIR |
Change if you want logs elsewhere |
After editing EconomyConfig, re-paste the updated Shared Helpers block into every action and recompile each one.
Run !seasonreset in chat while the broadcaster account is live. This:
- Closes the current season (sets
end_date) - Creates a new season row
- Inserts blank
seasonal_statsrows for all users in the new season - Broadcasts a
season_resetevent to the overlay - Posts confirmation in chat
What is preserved: lifetime_points, lifetime_wins, lifetime_losses, lifetime_total_bets, lifetime_points_wagered, lifetime_peak_rank_id
What resets: seasonal_points, rank_id, rank_change (in seasonal_stats for the new season)
| Symptom | Fix |
|---|---|
Compiled Successfully but action does nothing |
Check that CPH.TryGetArg key names match SB's actual arg keys. Print all args with a test action. |
| Log file not created | Verify C:\StreamerBot\Data\Logs\ exists and the SB process has write permission |
| WebSocket not connecting | Ensure WS server is enabled in SB (Step 4) and port 8080 is not blocked by firewall |
| Icons not showing | Verify filenames are lowercase .svg and the path in OBS resolves (see Step 7 options) |
| Database locked error | Ensure journal_mode=WAL was set when schema was created (check with PRAGMA journal_mode; in DB Browser) |
No 'users' arg found in Watch Time log |
The timer trigger in SB v1.0.4 must have "Present Viewers" action configured — check the timer sub-action passes the user list |
| Eternal rank not updating | Check the 15-min timer is enabled and the v_eternal_candidates view exists in the DB |
The plugin simply opens economy.db in read-only WAL mode:
// Java example
String url = "jdbc:sqlite:C:/StreamerBot/Data/economy.db";
Properties props = new Properties();
props.setProperty("open_mode", "1"); // SQLITE_OPEN_READONLY
Connection conn = DriverManager.getConnection(url, props);It can safely SELECT from any view (v_season_leaderboard, v_win_rate_leaderboard, v_eternal_candidates) or table without blocking Streamer.bot writes, because WAL mode allows unlimited concurrent readers.