# How to Add Support for New Games to HoshinoBot: A Complete Kancolle Integration Guide

> Learn how to add support for new games, like Kancolle, to HoshinoBot. Integrate new game modules by creating Python packages and registering command handlers.

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

---

**To add support for new games like Kancolle (艦隊これくしょん) to HoshinoBot, create a Python package under `hoshino/modules/`, instantiate the `Service` class from [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py), and register command handlers using decorators like `@sv.on_fullmatch` or `@sv.scheduled_job`.**

HoshinoBot operates on a **service-oriented architecture** where each game or feature exists as a modular service. By following the existing Kancolle implementation in `hoshino/modules/kancolle/`, you can integrate new games with command handling, scheduled reminders, and external API queries while leveraging the bot's built-in permission system.

## Understanding the Service Architecture

The core of HoshinoBot's extensibility lies in the `Service` class defined in **[`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py)**. Each game module creates a `Service` instance that registers the module with the bot's core, provides permission handling via `_check_all`, and creates a dedicated logger. When the bot starts, it iterates over the `MODULES` list in the configuration and imports each module, automatically executing the service registration code at the top level.

## Create the Module Package

Begin by creating a new directory under `hoshino/modules/` for your game. For Kancolle, this is `hoshino/modules/kancolle/`. Add an empty [`__init__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/__init__.py) file to make it a proper Python package. If your game requires sub-modules for data queries, create subdirectories like `query/` with their own [`__init__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/__init__.py) files. This isolation keeps game-specific code organized and ensures Python can resolve imports correctly.

## Instantiate the Service Class

In your main module file (e.g., [`reminder.py`](https://github.com/ice9coffee/hoshinobot/blob/main/reminder.py)), import and instantiate the `Service` class with a unique name, bundle identifier, and help text:

```python
from hoshino import Service

sv = Service('kc-reminder', bundle='kancolle', help_='Kancolle 定时提醒功能')

```

The `bundle` parameter groups related services together, while the service name must be unique across the entire bot instance. This instantiation registers your module with HoshinoBot's internal service registry and initializes the permission checking system.

## Register Command Handlers

Use the decorators provided by your `Service` instance to bind chat commands to coroutines. The **`@sv.on_fullmatch`** decorator triggers on exact text matches, while **`@sv.on_prefix`** and **`@sv.on_message`** offer pattern-based matching:

```python
@sv.on_fullmatch('演习提醒')
async def enshu_reminder(bot, ev):
    await bot.send(ev, '演習即将刷新！记得出击哦~')

```

These decorators automatically hook your coroutine into the bot's event loop and apply group-level permission checks before execution. The `bot` parameter provides the API interface, while `ev` contains the event context including `user_id` and group information.

## Schedule Periodic Jobs

For games requiring timed reminders or daily resets, use the **`@sv.scheduled_job`** decorator, which integrates with APScheduler. The following example from [`hoshino/modules/kancolle/reminder.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/kancolle/reminder.py) sends a daily notification at 03:30 Shanghai time:

```python
@sv.scheduled_job('cron', hour='3', minute='30')
async def daily_quest_refresh_reminder():
    await sv.broadcast('提督，今天的任务已经刷新！快去完成吧~')

```

Scheduled jobs respect the service's enabled status, meaning they only broadcast to groups that have explicitly enabled your game service. The jobs are executed by the built-in APScheduler and run in the `Asia/Shanghai` timezone.

## Query External Game APIs

When your game requires live data (fleet composition, expedition status, or player rankings), create a `query/` sub-package with async functions. Following the Kancolle pattern in **[`hoshino/modules/kancolle/query/fleet.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/kancolle/query/fleet.py)**:

```python
import aiohttp

API_URL = 'https://api.kcwiki.moe/kancolle/fleet/'

async def get_fleet_info(member_id: int) -> dict:
    async with aiohttp.ClientSession() as sess:
        async with sess.get(f'{API_URL}{member_id}') as resp:
            return await resp.json()

```

Keep network logic separate from command handlers to maintain clean separation between "bot glue" and "game API" concerns. Import these query functions into your main service file to fetch data before formatting responses.

## Persist Game State with SQLite

For storing rankings, cooldowns, or user progress, use a SQLite database under `~/.hoshino/`. Reference the `GameMaster` pattern from **[`hoshino/modules/priconne/games/desc_guess.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/priconne/games/desc_guess.py)**:

```python
import os
from hoshino.modules.priconne.games.game_master import GameMaster

DB_PATH = os.path.expanduser("~/.hoshino/kancolle_data.db")
gm = GameMaster(DB_PATH)

```

The `GameMaster` class abstracts SQLite operations, or you can implement your own thin wrapper using standard `sqlite3` or `aiosqlite` for async operations.

## Register the Module in Configuration

Finally, add your module to the bot's configuration. List the module path in the `MODULES` array within your config file (typically [`hoshino/config/__bot__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/config/__bot__.py)). For example, append `'hoshino.modules.kancolle'` to the list. HoshinoBot automatically imports and initializes all listed modules on startup, executing the `Service` construction code immediately upon import.

## How Message Processing Works

When a message arrives, **NoneBot** dispatches it to HoshinoBot's `on_message` hook. The framework then calls `Service._check_all` to verify permissions and group enable status before invoking your decorated coroutine. For scheduled jobs, `Service.scheduled_job` registers the coroutine with APScheduler; when triggered, the wrapper logs execution, catches exceptions, and uses `Service.broadcast` to push messages to all enabled groups.

## Summary

- **Create a package** under `hoshino/modules/<game>/` with proper [`__init__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/__init__.py) files to isolate your game code
- **Instantiate `Service`** with a unique name and bundle identifier to register with the bot core and enable permission handling
- **Use decorators** like `@sv.on_fullmatch` for commands and `@sv.scheduled_job` for periodic reminders
- **Separate API logic** into a `query/` sub-package using async functions to keep network code organized
- **Persist data** via SQLite in `~/.hoshino/` following existing `GameMaster` patterns for state management
- **Enable the module** by adding the full module path to the `MODULES` configuration list before starting the bot

## Frequently Asked Questions

### How do I enable my new game module after creating the files?

Add the module path to the `MODULES` list in your HoshinoBot configuration file, typically located at [`hoshino/config/__bot__.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/config/__bot__.py). Append the Python import path (e.g., `'hoshino.modules.kancolle'`) to the array. The bot automatically imports and initializes the service when it starts; no additional registration code is required beyond creating the `Service` instance in your module.

### What is the difference between `@sv.on_fullmatch` and `@sv.on_prefix`?

**`@sv.on_fullmatch('command')`** triggers only when the message content exactly matches the specified string, while **`@sv.on_prefix('command')`** triggers when the message starts with the specified string, allowing you to capture arguments after the command. Both decorators automatically apply the service's permission checks through the internal `_check_all` method defined in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py) before executing your handler.

### Can I use databases other than SQLite for game state persistence?

Yes, though SQLite is the convention used in existing modules like [`hoshino/modules/priconne/games/desc_guess.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/priconne/games/desc_guess.py). You can implement any async-compatible database by initializing the connection in your module file and using it within your command handlers. Ensure database files are stored under `~/.hoshino/` to maintain consistency with the project's directory structure.

### How do I restrict commands to specific groups or users?

The `Service` class automatically handles group-level enable/disable functionality through its configuration system. Groups must explicitly enable your service using the bot's master control commands before receiving any messages or triggering handlers. For finer control, inspect `ev.group_id` or `ev.user_id` within your handler coroutine, or implement custom permission logic using the bot's superuser configuration.