Run your own NextBall room around the clock on your own computer or server, run by a script: welcome messages, auto teams, winner stays on, your own commands. The match runs on your machine and players connect to it directly, so a room on a server near your players gives them a low ping.
A token lets your script open rooms for your account. It works for 30 minutes (rooms you open stay open after that). Up to 3 rooms per account can run at the same time. Log in on NextBall first.
Keep your token to yourself: anyone with it can open rooms in your name until it runs out.
In your browser: open nextballz.com/headless.html, paste the token, press Open room (or write a script in the box there and press Run script). Keep that tab open: closing it closes the room. A tab in the background keeps running.
On a server, without a screen (Node.js + Puppeteer):
// npm i puppeteer
const puppeteer = require('puppeteer');
const fs = require('fs');
(async () => {
const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();
page.on('console', (m) => console.log(m.text()));
await page.goto('https://nextballz.com/headless.html');
// room.js is your script (it calls NBInit, see below)
await page.evaluate(fs.readFileSync('room.js', 'utf8'));
})();
Pick a server close to your players (a room in São Paulo for Brazil, Frankfurt for Europe...). A small machine is enough: one room uses a fraction of one CPU core and a few hundred KB/s of upload per 10 players.
const room = NBInit({
token: 'YOUR-TOKEN',
roomName: 'BR 3v3 · winner stays',
playerName: 'Bot', // the name your room's messages show under
maxPlayers: 12,
mode: 'futsal', // any mode of the lobby: classic, futsal, real, chaos, icehockey, basketball...
options: { court: 'futsal-x3' }, // real: { pitch: 'realMatch_small' | 'realMatch_medium' | 'realMatch_large', ball: 'small' | 'big' }
scoreLimit: 3,
timeLimit: 3,
password: '', // optional
public: true, // false: not in the room list, only the link leads in
rated: true // matches count for the players' rank (modes with a rank)
});
room.onRoomLink = (link) => console.log('Room:', link);
room.onPlayerJoin = (player) => {
room.sendChat('Welcome ' + player.name + '! Type !help', player.id);
const reds = room.getPlayerList().filter(p => p.team === 1).length;
const blues = room.getPlayerList().filter(p => p.team === 2).length;
if (reds < 3 || blues < 3) room.setPlayerTeam(player.id, reds <= blues ? 1 : 2);
if (reds + blues + 1 >= 6) room.startGame();
};
room.onPlayerChat = (player, message) => {
if (message === '!help') room.sendChat('Commands: !bb (leave)', player.id);
if (message === '!bb') room.kickPlayer(player.id, 'Bye!');
};
room.onTeamVictory = (scores) => {
room.sendChat((scores.winner === 1 ? 'Red' : 'Blue') + ' wins ' + scores.red + '-' + scores.blue);
setTimeout(() => room.startGame(), 5000);
};
A player is { id, name, team, admin, userId, country, guest }. Teams: 0 spectators, 1 red, 2 blue.
sendChat(msg, playerId?) | A message from your room, to everyone or only to one player. |
setPlayerTeam(id, team) | Moves a player. |
setPlayerAdmin(id, on) | Gives or takes a player's admin rights (they can start, stop and move players). |
kickPlayer(id, reason, ban?) | Removes a player; with ban: true they can't come back to this room. |
startGame() · stopGame() | Kick-off / stop. |
pauseGame(true / false) | Pause; false resumes after a 3 second countdown. |
setScoreLimit(n) · setTimeLimit(min) | Match limits (0 = none). |
setStadium(name) | A stadium of the room's mode. |
setRated(on) | Rated on / off between matches. |
setMode(mode, options?) | Another game mode (stop the game first), also 'real' (Real Match) and 'chaos'. |
randomizeTeams() · autoBalance() · resetTeams() · lockTeams() | The lobby's team buttons (lockTeams toggles). |
getPlayerList() · getPlayer(id) | Who is in the room (your host is not in the list). |
getScores() | { red, blue, time, state } |
getBallPosition() · getPlayerDisc(id) | { x, y, vx, vy } while a match runs. |
getRoomLink() · getRoomId() | The invite link / id. |
Events (set them as functions):
onRoomLink(link) | The room is open. |
onPlayerJoin(player) · onPlayerLeave(player) | Someone came / left. |
onPlayerChat(player, message) | A chat line. |
onPlayerTeamChange(player) · onPlayerAdminChange(player) | Team / admin changed. |
onGameStart() · onGameStop() · onGamePause() · onGameUnpause() | Match flow. |
onTeamGoal(team, goal) | goal = { scorer, scorerName, assistName, ownGoal, score } |
onTeamVictory(scores) | { red, blue, winner } at the final whistle. |
onRoomClosed(reason) · onError(message) | The room ended / could not open. |
A room opened with rated: true counts for the players' rank with the same rules as every rated room:
a fair line-up, players with an account, and the result is checked by NextBall (a host can't write a score).
The same room rules apply as everywhere on NextBall;
a room that spams, misleads players or copies an official name is closed and the account can lose hosting.
Up to 3 rooms per account and 6 per server address.