How to Manage and Implement Clan Battle (公会战) Features in HoshinoBot

To manage clan battles in HoshinoBot, enable a version (v2/v3/v4) via !启用会战, then use commands like !建会, !出刀, and !进度 which route through BattleMaster to persist data in SQLite and JSON files.

The 公会战 (clan battle) subsystem in ice9coffee/hoshinobot is implemented as a modular plugin under hoshino/modules/pcrclanbattle. It provides a complete guild management solution for Princess Connect! Re:Dive, handling everything from member registration to damage reporting and statistics generation.

Architecture of the Clan Battle Subsystem

The system follows a service-command-DAO pattern with three distinct layers:

When a user sends a command prefixed with ! or !, the _clanbattle_bus listener in hoshino/modules/pcrclanbattle/clanbattle/__init__.py extracts the command name, looks it up in the module-level _registry dictionary, parses arguments using ArgParser, and dispatches to the handler coroutine. Handlers delegate all data operations to BattleMaster, which acts as a façade hiding DAO implementation details.

Enabling Specific Clan Battle Versions

HoshinoBot ships with three major clan battle implementations. Only one can be active per group at a time.

Version Entry Point Characteristics
v2 clanbattle/__init__.py Full command suite with comprehensive features
v3 clanbattle_v3.py Simplified UI without web panel support
v4 clanbattle_v4.py Post-June-2021 server support (web panel under development)

To activate a version, a super-user executes the Version Selector command defined in hoshino/modules/pcrclanbattle/version_selector.py:

@sv.on_prefix('会战启用', '启用会战')
async def version_select(bot, ev: CQEvent):
    gid = ev.group_id
    arg = ev.message.extract_plain_text()  # "v2", "v3", or "v4"

    svs = Service.get_loaded_services()
    # Enables selected version for this specific group only

Execute this in your group chat:

!启用会战 v2

The selector calls set_enable(gid) on the chosen service and disables others, making the command suite immediately available to that group.

Core Clan Battle Workflow

Once enabled, the standard operational workflow involves five key phases:

1. Clan and Member Management

Create a guild and add members using the administrative commands:

!建会 N星际舰队 Sjp          # Creates "星际舰队" on JP server

!入会 小明 @123456789       # Adds member "小明" with QQ ID 123456789

Internally, !建会 triggers BattleMaster.add_clan(1, args.N, args.S) which inserts a row into the SQLite clan table with columns (gid, cid, name, server). The !入会 command calls BattleMaster.add_member(uid, qq_id, name, clan_id) to populate the member table.

2. Damage Reporting

Members report boss damage using the !出刀 command:

!出刀 12345 @987654321 R5 B3   # 12,345 damage on Round 5, Boss 3

The handler add_challenge in cmdv2.py builds a ParseResult dictionary and passes it to BattleMaster.process_challenge. This method:

  1. Retrieves current boss HP via get_challenge_progress
  2. Validates damage against remaining HP (auto-correcting over-damage by 30,000 threshold)
  3. Marks tail-cuts automatically when damage exceeds boss HP
  4. Persists the record via BattleDao.add into the battle table with schema (gid, cid, yyyy, mm, eid, uid, alt, time, round, boss, dmg, flag)

3. Progress Monitoring

Check current boss status with:

!进度

This invokes BattleMaster.get_challenge_progress returning (round, boss, hp), then formats output via _gen_progress_text:


星际舰队 当前进度:
3周目 ③王    SCORE x1.2
HP=45,300/68,000

4. Subscriptions and Locking

Manage boss reservations and locks using:

!预约 3 M准备就绪    # Subscribe to Boss 3 with message "准备就绪"

!锁定               # Lock current boss for your clan

!挂树               # Report "hanging" status (waiting for rescue)

Subscription data is not stored in SQLite. Instead, SubscribeData class serializes reservations, locks, and hang-tree status to JSON files located at ~/.hoshino/clanbattle_sub/<group_id>.json using json.dump.

5. Statistics Generation

Generate visual reports with matplotlib:

!伤害统计           # Damage per member stacked bar chart

!分数统计           # Score statistics

The stat_damage method in BattleMaster pulls per-member damage arrays, matplotlib renders the chart, and util.fig2b64 converts it to base64 for message transmission.

Data Persistence Details

The subsystem uses a hybrid storage approach:

SQLite Database (~/.hoshino/clanbattle.db):

  • clan table: Guild configuration (gid, cid, name, server)
  • member table: Member roster (uid, alt, name, gid, cid)
  • battle table: Challenge records with full damage history

JSON Files (~/.hoshino/clanbattle_sub/):

  • Per-group subscription state for reservations (预约), locks (锁定), and hang-tree status (挂树)
  • Accessed through SubscribeData helper methods: add_sub, remove_sub, set_lock

DAO classes (ClanDao, MemberDao, BattleDao) in hoshino/modules/pcrclanbattle/clanbattle/dao/sqlitedao.py abstract raw SQL operations, providing type-safe CRUD methods like find_by(gid=..., cid=...) for member queries.

Extending and Customizing Features

To add new clan battle commands or modify workflows:

  1. Define argument parsing in argparse/__init__.py using ArgParser and ArgHolder classes to specify command syntax
  2. Register the handler with the @cb_cmd('命令名', ArgParser(...)) decorator in cmdv2.py (or the active version file)
  3. Implement business logic by adding methods to BattleMaster in battlemaster.py or calling existing façade methods
  4. Extend persistence if needed by modifying sqlitedao.py to add new DAO classes or alter existing table schemas (requires manual database migration)

All privilege checks use priv.ADMIN constants, ensuring only group administrators or owners can execute destructive operations like !清空成员 or !删会.

Summary

Frequently Asked Questions

How do I switch from clan battle v2 to v3 in HoshinoBot?

Send !启用会战 v3 in your group chat. The version_select handler in version_selector.py will disable the v2 service and enable v3 for that specific group ID. Only super-users can execute this command, and the change takes effect immediately without restarting the bot.

Where is clan battle data stored in HoshinoBot?

Permanent data resides in ~/.hoshino/clanbattle.db (SQLite) with three tables: clan, member, and battle. Temporary subscription data (reservations, locks, hang-tree status) is stored as JSON files in ~/.hoshino/clanbattle_sub/<group_id>.json. The sqlitedao.py file contains the DAO implementation handling all database operations.

What is the difference between !出刀 and process_challenge?

!出刀 is the user-facing chat command. When invoked, it triggers the add_challenge handler in cmdv2.py, which parses arguments and calls BattleMaster.process_challenge. The latter contains the business logic: validating damage against boss HP, detecting tail-cuts, and persisting the record via BattleDao.add. This separation ensures command parsing remains independent from battle calculation logic.

Can I modify the boss HP values for custom clan battles?

Yes. Edit hoshino/config_example/pcrclanbattle.py (or your active config directory) to adjust BOSS_HP and SCORE_RATE arrays. These values are loaded by BattleMaster during initialization. After modifying the configuration, restart the bot or reload the module for changes to take effect in damage calculations and progress tracking.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →