feat(status): show money-supply metric in /status
Adds economy.get_economy_stats() (single-scan total coins, house balance, player-held coins, player count) and a "Rahavaru" field to /status, so admins can see whether the sinks are keeping pace with minted income. Also removed a duplicate bot_admin_check import. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013VbAVsrZuYesea99mPMmPT
This commit is contained in:
@@ -13,9 +13,9 @@ from pathlib import Path
|
|||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
|
|
||||||
|
from core import economy
|
||||||
from core.admin import bot_admin_check
|
from core.admin import bot_admin_check
|
||||||
import strings as S
|
import strings as S
|
||||||
from core.admin import bot_admin_check
|
|
||||||
|
|
||||||
|
|
||||||
def register_ops_admin_commands(
|
def register_ops_admin_commands(
|
||||||
@@ -45,6 +45,7 @@ def register_ops_admin_commands(
|
|||||||
latency_ms = round(bot.latency * 1000, 1)
|
latency_ms = round(bot.latency * 1000, 1)
|
||||||
cache_size = get_member_cache_size()
|
cache_size = get_member_cache_size()
|
||||||
user_count = await count_economy_users()
|
user_count = await count_economy_users()
|
||||||
|
eco_stats = await economy.get_economy_stats()
|
||||||
|
|
||||||
embed = discord.Embed(title=S.STATUS_UI["title"], color=0x57F287)
|
embed = discord.Embed(title=S.STATUS_UI["title"], color=0x57F287)
|
||||||
embed.add_field(
|
embed.add_field(
|
||||||
@@ -82,6 +83,18 @@ def register_ops_admin_commands(
|
|||||||
value=str(cache_size),
|
value=str(cache_size),
|
||||||
inline=True,
|
inline=True,
|
||||||
)
|
)
|
||||||
|
total = eco_stats["total_coins"]
|
||||||
|
house_pct = round(eco_stats["house_balance"] / total * 100) if total else 0
|
||||||
|
embed.add_field(
|
||||||
|
name=S.STATUS_UI["supply_field"],
|
||||||
|
value=S.STATUS_UI["supply_val"].format(
|
||||||
|
total=f"{total:,}".replace(",", " "),
|
||||||
|
players=f"{eco_stats['player_coins']:,}".replace(",", " "),
|
||||||
|
house=f"{eco_stats['house_balance']:,}".replace(",", " "),
|
||||||
|
house_pct=house_pct,
|
||||||
|
),
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
|
||||||
log_lines = [
|
log_lines = [
|
||||||
S.STATUS_UI["log_line"].format(name=p.name, size_kb=f"{p.stat().st_size / 1024:.1f}")
|
S.STATUS_UI["log_line"].format(name=p.name, size_kb=f"{p.stat().st_size / 1024:.1f}")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from .. import pb_client
|
from .. import pb_client
|
||||||
|
from . import house
|
||||||
from .levels import get_level
|
from .levels import get_level
|
||||||
|
|
||||||
|
|
||||||
@@ -109,3 +110,30 @@ async def get_all_leaderboards() -> dict[str, list[tuple]]:
|
|||||||
"fish": [(r["user_id"], r.get("total_fish_caught", 0))
|
"fish": [(r["user_id"], r.get("total_fish_caught", 0))
|
||||||
for r in desc(lambda r: r.get("total_fish_caught", 0))],
|
for r in desc(lambda r: r.get("total_fish_caught", 0))],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def get_economy_stats() -> dict[str, int]:
|
||||||
|
"""Money-supply snapshot from a single scan: total coins in circulation, how
|
||||||
|
much players hold vs. the house. Lets /status show whether the sinks (house,
|
||||||
|
vanity burn, bail, fines) are keeping pace with minted income."""
|
||||||
|
records = await pb_client.list_all_records()
|
||||||
|
house_id = str(house.HOUSE_ID) if house.HOUSE_ID is not None else None
|
||||||
|
total = 0
|
||||||
|
house_balance = 0
|
||||||
|
player_count = 0
|
||||||
|
for r in records:
|
||||||
|
uid = r.get("user_id")
|
||||||
|
if not uid:
|
||||||
|
continue
|
||||||
|
bal = r.get("balance", 0) or 0
|
||||||
|
total += bal
|
||||||
|
if uid == house_id:
|
||||||
|
house_balance = bal
|
||||||
|
else:
|
||||||
|
player_count += 1
|
||||||
|
return {
|
||||||
|
"total_coins": total,
|
||||||
|
"house_balance": house_balance,
|
||||||
|
"player_coins": total - house_balance,
|
||||||
|
"player_count": player_count,
|
||||||
|
}
|
||||||
|
|||||||
@@ -243,6 +243,8 @@ STATUS_UI: dict[str, str] = {
|
|||||||
"tasks_field": "🔄 Async tasks",
|
"tasks_field": "🔄 Async tasks",
|
||||||
"eco_players_field": "👤 Eco players",
|
"eco_players_field": "👤 Eco players",
|
||||||
"members_cache_field": "📋 Liikmed (cache)",
|
"members_cache_field": "📋 Liikmed (cache)",
|
||||||
|
"supply_field": "💰 Rahavaru",
|
||||||
|
"supply_val": "Kokku {total}\nMängijatel {players}\nKassas {house} ({house_pct}%)",
|
||||||
"log_files_field": "📂 Log files",
|
"log_files_field": "📂 Log files",
|
||||||
"log_line": "`{name}` - {size_kb} KB",
|
"log_line": "`{name}` - {size_kb} KB",
|
||||||
"none": "-",
|
"none": "-",
|
||||||
|
|||||||
@@ -47,3 +47,31 @@ class TestGetAllLeaderboards:
|
|||||||
fish = run(economy.get_all_leaderboards())["fish"]
|
fish = run(economy.get_all_leaderboards())["fish"]
|
||||||
counts = [c for _, c in fish]
|
counts = [c for _, c in fish]
|
||||||
assert counts == sorted(counts, reverse=True)
|
assert counts == sorted(counts, reverse=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEconomyStats:
|
||||||
|
def test_totals_split_house_from_players(self, fake_pb, monkeypatch):
|
||||||
|
monkeypatch.setattr(economy.house, "HOUSE_ID", 999)
|
||||||
|
monkeypatch.setattr(economy.house, "_house_pb_id", None)
|
||||||
|
# three players + the house
|
||||||
|
for uid, bal in [(1, 100), (2, 250), (3, 0)]:
|
||||||
|
run(economy.get_user(uid))
|
||||||
|
fake_pb.record_for(uid)["balance"] = bal
|
||||||
|
run(economy.get_user(999))
|
||||||
|
fake_pb.record_for(999)["balance"] = 5000
|
||||||
|
|
||||||
|
stats = run(economy.get_economy_stats())
|
||||||
|
assert stats["total_coins"] == 100 + 250 + 0 + 5000
|
||||||
|
assert stats["house_balance"] == 5000
|
||||||
|
assert stats["player_coins"] == 350
|
||||||
|
assert stats["player_count"] == 3 # house excluded
|
||||||
|
|
||||||
|
def test_no_house_configured(self, fake_pb, monkeypatch):
|
||||||
|
monkeypatch.setattr(economy.house, "HOUSE_ID", None)
|
||||||
|
run(economy.get_user(1))
|
||||||
|
fake_pb.record_for(1)["balance"] = 42
|
||||||
|
stats = run(economy.get_economy_stats())
|
||||||
|
assert stats["total_coins"] == 42
|
||||||
|
assert stats["house_balance"] == 0
|
||||||
|
assert stats["player_coins"] == 42
|
||||||
|
assert stats["player_count"] == 1
|
||||||
|
|||||||
Reference in New Issue
Block a user