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

> Easily manage HoshinoBot clan battle features using commands like !建会 !出刀 and !进度 Enable v2 v3 or v4 and persist data with BattleMaster and SQLite JSON files

- Repository: [ice9coffee/hoshinobot](https://github.com/ice9coffee/hoshinobot)
- Tags: how-to-guide
- Published: 2026-03-03

---

**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](https://github.com/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:

- **Service & Command Registration**: Exposes bot commands and manages version selection via [`version_selector.py`](https://github.com/ice9coffee/hoshinobot/blob/main/version_selector.py) and [`clanbattle/__init__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/clanbattle/__init__.py)
- **Business Logic**: Handles calculations, progress tracking, and statistics through [`battlemaster.py`](https://github.com/ice9coffee/hoshinobot/blob/main/battlemaster.py)
- **Persistence**: Stores data in SQLite via DAO classes in [`dao/sqlitedao.py`](https://github.com/ice9coffee/hoshinobot/blob/main/dao/sqlitedao.py) and JSON files for subscriptions

When a user sends a command prefixed with `!` or `！`, the `_clanbattle_bus` listener in [`hoshino/modules/pcrclanbattle/clanbattle/__init__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/clanbattle/__init__.py) | Full command suite with comprehensive features |
| **v3** | [`clanbattle_v3.py`](https://github.com/ice9coffee/hoshinobot/blob/main/clanbattle_v3.py) | Simplified UI without web panel support |
| **v4** | [`clanbattle_v4.py`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/pcrclanbattle/version_selector.py):

```python
@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:

```bash
!启用会战 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:

```bash
!建会 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:

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

```

The handler `add_challenge` in [`cmdv2.py`](https://github.com/ice9coffee/hoshinobot/blob/main/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:

```bash
!进度

```

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:

```bash
!预约 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:

```bash
!伤害统计           # 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`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/cmdv2.py) (or the active version file)
3. **Implement business logic** by adding methods to `BattleMaster` in [`battlemaster.py`](https://github.com/ice9coffee/hoshinobot/blob/main/battlemaster.py) or calling existing façade methods
4. **Extend persistence** if needed by modifying [`sqlitedao.py`](https://github.com/ice9coffee/hoshinobot/blob/main/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

- **Enable the module** per group using `!启用会战 v2` (or v3/v4) via [`version_selector.py`](https://github.com/ice9coffee/hoshinobot/blob/main/version_selector.py)
- **Manage entities** through `BattleMaster` methods: `add_clan`, `add_member`, `process_challenge`
- **Store data** in SQLite for permanent records (clans, members, battles) and JSON for transient state (subscriptions, locks)
- **Extend functionality** by registering new `@cb_cmd` handlers that delegate to the DAO layer via the `BattleMaster` façade
- **Key files**: [`hoshino/modules/pcrclanbattle/clanbattle/battlemaster.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/pcrclanbattle/clanbattle/battlemaster.py) for logic, [`hoshino/modules/pcrclanbattle/clanbattle/dao/sqlitedao.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/pcrclanbattle/clanbattle/dao/sqlitedao.py) for persistence, and [`hoshino/modules/pcrclanbattle/version_selector.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/pcrclanbattle/version_selector.py) for version management

## 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`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/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`](https://github.com/ice9coffee/hoshinobot/blob/main/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.