Skip to content

Frontend Development Guide

Welcome to the comprehensive guide for building frontends that integrate with bancho.py-ex. This guide covers the PubSub system that enables real-time communication between your frontend and the server.

What are PubSubs?

PubSubs (Publish-Subscribe) are real-time communication channels that allow external applications to interact with the bancho.py-ex server. Each channel either sends data from the server or receives commands from your application.

Getting Started

  • Sends - Server pushes data to your application
  • Receives - Your application sends commands to server
  • All data is transmitted in JSON format

Implementation example

public void onEnable(String, pluginName, Logger logger) {
    PubSubModels.RankOutput rankOutput = new PubSubModels().new RankOutput();
    rankOutput.setBeatmap_id("1");
    rankOutput.setStatus(2); // ranked
    rankOutput.setFrozen(true);

    long subscribers = App.jedisPool.publish("rank", new Gson().toJson(rankOutput));
}
@router.post("/web/osu-submit-modular.php")
async def osuSubmitModular(...) -> Response:
    score = Score.from_submission(score_data[2:])
    pubsub = app.state.services.redis.pubsub()
    await pubsub.execute_command("PUBLISH", "ex:submit", score.toJSON())

Score / Map management

Score Submissions

ex:submit

Direction: Server sends to your application
Purpose: Real-time score submissions and statistics

{
  "id": 219154,
  "mode": 0,
  "mods": 88,
  "pp": 221283.124,
  "sr": 90.73485416518942,
  "score": 88845,
  "max_combo": 3,
  "acc": 2.158273381294964,
  "n300": 3,
  "n100": 0,
  "n50": 0,
  "nmiss": 136,
  "ngeki": 1,
  "nkatu": 0,
  "grade": 1,
  "passed": false,
  "perfect": false,
  "status": 0,
  "client_time": "2025-02-02T11:10:58",
  "server_time": "2025-02-02T11:10:57.000379",
  "time_elapsed": 54540,
  "client_flags": 0,
  "client_checksum": "EXAMPLE",
  "rank": null,
  "beatmap_id": 372245,
  "player_id": 1316
}
Field Type Description
id int Unique score ID
mode int Game mode (0=std, 1=taiko, 2=catch, 3=mania)
mods int Mod combination bitwise
pp float Performance points
sr float Star rating
score int Total score
max_combo int Maximum combo achieved
acc float Accuracy percentage
passed bool Whether the map was passed
beatmap_id int Beatmap identifier
player_id int Player identifier

Beatmap Status Changes

ex:map_status_change

Direction: Server sends to your application
Purpose: Beatmap ranking status updates

{
  "map_ids": [4840847, 4888854, 4892923, 4894589, 4918951],
  "ranktype": "set",
  "type": "love"
}
Field Type Description
map_ids int[] Array of beatmap IDs affected
ranktype string Ranking operation type (set, update)
type string New status (love, ranked, approved, pending)

Beatmap Ranking

:material-receive: rank

Direction: Your application sends to server
Purpose: Manually rank/unrank beatmaps

{
  "beatmap_id": 4870830,
  "status": 2,
  "frozen": true
}
Field Type Description
beatmap_id int Target beatmap ID
status int Ranking status (0=pending, 1=ranked, 2=approved, 3=qualified, 4=loved)
frozen bool Whether to freeze the beatmap from further changes

User Management

User Restriction

:material-receive: restrict

Direction: Your application sends to server
Purpose: Restrict user accounts

{
  "id": 3,
  "userId": 3,
  "reason": "the owner cheats"
}
Field Type Description
id int Target user ID to restrict
userId int Admin user ID performing the action
reason string Reason for restriction

User Unrestriction

:material-receive: unrestrict

Direction: Your application sends to server
Purpose: Unrestrict user accounts

{
  "id": 3,
  "userId": 3,
  "reason": "isn't a bad guy"
}
Field Type Description
id int Target user ID to unrestrict
userId int Admin user ID performing the action
reason string Reason for unrestriction

User Data Wipe

:material-receive: wipe

Direction: Your application sends to server
Purpose: Wipe user statistics for specific game mode

{
  "id": 3,
  "mode": 0
}
Field Type Description
id int Target user ID
mode int Game mode to wipe (0=std, 1=taiko, 2=catch, 3=mania)

Communication

Global Announcements

:material-receive: alert_all

Direction: Your application sends to server
Purpose: Send announcements to all online users

{
  "message": "Server maintenance in 10 minutes!"
}
Field Type Description
message string Announcement message to broadcast

Premium Features

Supporter Status

:material-receive: givedonator

Direction: Your application sends to server
Purpose: Grant supporter/donator status

{
  "id": 3,
  "duration": "1w"
}
Field Type Description
id int Target user ID
duration string Duration (s=seconds, m=minutes, h=hours, d=days, w=weeks)

Privileges Management

Available Privileges

normalverifiedwhitelistedsupporterpremiumalumnitournamentnominatormodadmindeveloper

Add Privileges

:material-receive: addpriv

Direction: Your application sends to server
Purpose: Grant user privileges

{
  "id": 3,
  "privs": ["admin", "developer"]
}
Field Type Description
id int Target user ID
privs string[] Array of privileges to add

Remove Privileges

:material-receive: removepriv

Direction: Your application sends to server
Purpose: Remove user privileges

{
  "id": 3,
  "privs": ["admin", "developer"]
}
Field Type Description
id int Target user ID
privs string[] Array of privileges to remove