@dao3fun/live-sdk
v0.2.0
Published
支持赛程定位、队伍/玩家查询、赛程进度/倒计时,队员信息上传、以及事件订阅。
Keywords
Readme
神岛赛事直播工具
支持赛程定位、队伍/玩家查询、赛程进度/倒计时、队员信息上传,以及事件订阅。
注意:本 SDK 不提供 KDA/分数/排行榜/MVP 等统计计算;LiveEvent 仅管理“配置的比赛信息”,LiveUpdater 负责把你的实时数据(比分、玩家扩展等)上报到平台。
安装
npm install @dao3fun/live-sdk快速开始
import { LiveEvent } from '@dao3fun/live-sdk';
async function main() {
const live = LiveEvent.getInstance();
// 选择数据源:测试 or 生产(异步,内部会立即拉一次)
await live.useTestData(true); // 测试源(完整版,不随直播变动,便于联调)
// await live.useTestData(false); // 生产源(上线前请切回)
// 可选:固定“当前时间”做回放/测试,秒级时间戳,在两个队伍比赛时内有效
live.setNowSecOverride(1755498600);
// live.useRealTime(); // 取消覆盖,恢复实时
// 订阅数据更新
const off = live.onUpdate((payload) => {
console.log('Updated:', payload.title);
});
// 立即拉一次(可选;useTestData 已经会拉一次)
await live.refreshNow();
// 读取当前比赛与地图、赛程进度与倒计时
const curMatch = live.getCurrentMatch();
const curMap = live.getCurrentMatchMap();
const progress = live.getCurrentMatchProgress();
const countdown = live.getCountdownToNextMatch();
console.log({ curMatch, curMap, progress, countdown });
off();
}
main().catch(console.error);LiveUpdater 最简上报(当前场次)
import {
LiveEvent,
LiveUpdater,
type LiveUpdatePlayer,
} from '@dao3fun/live-sdk';
// 使用 LiveUpdater 上报
const updater = new LiveUpdater({ key: 'demo_player_extras' });
async function pushNow() {
// 获取 SDK 实例
const live = LiveEvent.getInstance();
await live.useTestData(true); // 示例:测试源
// 获取当前进行中的比赛
const cur = live.getCurrentMatch();
if (!cur) return;
// 覆盖“当前场次”的玩家扩展字段(按玩家 id)
const extras: Record<number, Partial<LiveUpdatePlayer>> = {
101: { score: 12, hp: 88, kda: '2/1/3' },
102: { score: 7 },
};
// 上报 当前比赛信息
// 他会自动记录对战历史,你只需要传入当前比赛的信息即可。
// 注意,当前比赛和队员的信息一定要匹配,否则无效。
const ok = await updater.pushFromMatch(cur, { teamA: 10, teamB: 9 }, extras);
// 返回结果
console.log('push ok?', ok);
}
// 执行
pushNow().catch(console.error);数据源:生产/测试切换
await live.useTestData(enable: boolean): Promise<void>- 功能:切换数据源为测试或生产环境,并立即异步拉取一次最新数据。
- 参数:
enable: boolean-true表示切换到测试数据源,false表示切换到生产数据源。 - 用途:方便在开发/联调时使用固定的测试数据,上线前再切换回实时生产数据。
live.isUsingTestData(): boolean- 功能:检查当前是否正在使用测试数据源。
await live.useCustomUrl(url: string): Promise<void>- 功能: 切换到自定义的数据源 URL,并立即异步拉取一次最新数据。
- 参数:
url: string- 自定义数据源的 URL。 - 用途: 用于连接到非官方或代理的数据接口。
- 语义:
- 测试源:完整静态数据,便于测试/联调(
DEFAULT_LIVE_URL_TEST) - 生产源:线上实时数据(
DEFAULT_LIVE_URL,上线前务必切回)
- 测试源:完整静态数据,便于测试/联调(
- 示例:
const live = LiveEvent.getInstance();
// 测试环境联调
await live.useTestData(true);
console.log('Using test?', live.isUsingTestData()); // true
// 发布到正式前
await live.useTestData(false);刷新与轮询
refreshNow(): Promise<void>- 功能:立即异步拉取一次最新数据。
- 用途:在需要确保获取到最新信息时(如执行统计前)手动调用。如果拉取失败,会触发
onError事件,并且外层调用可以catch捕获错误。
stop(): void- 功能:停止内部的自动轮询。
- 用途:在不需要实时更新数据时(如页面不可见或组件销毁时)调用,以节省资源。
resume(): void- 功能:恢复内部的自动轮询。
- 用途:在需要时重新开启自动数据更新。
setFetcher(fetcher): void- 功能:设置自定义的数据请求器。
- 参数:
fetcher- 一个函数,接收url作为参数,并返回一个包含json()方法的对象,如(url) => fetch(url)。 - 用途:用于高级定制,例如在请求中添加自定义的鉴权头、日志记录或使用 mock 数据。
- 默认行为:SDK 默认已开启短周期轮询,自动获取最新数据。
live.setFetcher(async (url) => {
const res = await fetch(url, { headers: { 'x-token': '...' } });
return { json: () => res.json() };
});全局时间覆盖(用于回放/对齐)
setNowSecOverride(sec?: number): void- 功能:覆盖 SDK 内部使用的“当前时间”,单位为 Unix 时间戳(秒)。
- 参数:
sec?: number- 可选的时间戳。如果传入undefined或不传,则清除覆盖,等同于useRealTime()。 - 用途:用于测试和回放。通过固定一个时间点,可以稳定地测试依赖于当前时间的功能(如
getCurrentMatch())。
useRealTime(): void- 功能:取消时间覆盖,让 SDK 恢复使用真实的系统时间。
- 用途:在测试或回放结束后,调用此方法以返回正常模式。
- 影响范围:所有接受可选
nowSec参数的方法,在未显式传入该参数时,都会优先使用这里设置的覆盖时间。
live.setNowSecOverride(1755498600);
const cur = live.getCurrentMatch(); // 将基于覆盖时间判断
live.useRealTime();事件订阅
onUpdate(cb): () => void- 功能:订阅数据更新事件。当拉取到的数据与上一次相比发生变化时,回调函数
cb会被调用。 - 参数:
cb: (payload: LivePayload) => void- 数据更新时的回调函数。 - 返回:一个函数,调用该函数可以取消此次订阅。
- 功能:订阅数据更新事件。当拉取到的数据与上一次相比发生变化时,回调函数
waitForNextUpdate(timeoutMs?): Promise<LivePayload>- 功能:返回一个 Promise,它会在下一次数据更新时 resolve,或在超时后 reject。
- 参数:
timeoutMs?: number- 可选的超时时间(毫秒)。 - 用途:用于需要等待特定更新才能继续执行的场景。
onError(cb): () => void- 功能:订阅数据拉取失败事件。
- 参数:
cb: (error: Error) => void- 发生错误时的回调函数。 - 返回:一个函数,调用该函数可以取消此次订阅。
onPlayerUpdate(playerId, cb): () => void- 功能:监听特定玩家在“当前比赛”中的引用变化(是否在场等)。
- 参数:
playerId: number- 要监听的玩家 ID。cb: (playerRef: PlayerRef | undefined) => void- 当玩家在场状态变化时触发;不在当前比赛则为undefined。
- 返回:取消订阅函数。
const offAll = live.onUpdate(console.log);
const offErr = live.onError(console.error);
const offP = live.onPlayerUpdate(123, (ref) => console.log('P123:', ref));
await live.waitForNextUpdate(10000); // 最多等 10s
offAll();
offErr();
offP();顶层信息读取
getType(): 'Game' | 'Live':获取赛事类型,例如是普通游戏还是直播活动。getEnv(): string:获取当前数据源的环境标识。getTitle(): string:获取赛事的完整标题。getDescription(): string:获取赛事的描述信息。getRoomId(): number:获取直播或比赛房间的 ID。getCover(): string:获取赛事的封面图片 URL。getStartTime(): number/getEndTime(): number:以 Unix 时间戳(秒)格式,获取赛事的开始和结束时间。getStartDate(): Date/getEndDate(): Date:以 JavaScriptDate对象格式,获取赛事的开始和结束时间。isLive(nowSec?): boolean:判断当前是否处于赛事直播时间段内。可以提供一个可选的nowSec参数来基于特定时间点进行判断。
赛事配置与地图
getGameCfg(): GameCfg | undefined:获取游戏的核心配置信息,如果存在的话。getLogo(): string | undefined:获取赛事的 Logo 图片 URL。getTeams(): Team[]:获取在赛事配置中定义的所有参赛队伍的列表。getMatchMaps(): MatchMap[]:获取本次赛事所有比赛地图的列表。getCommentators(): number[]:获取解说员的用户 ID 列表。getOperators(): number[]:获取中控台成员的用户 ID 列表。getBracket(): Bracket | null:获取晋级图信息,如果不存在则返回null。
赛程/比赛
getMatches(): Match[]:获取原始的比赛列表。getMatchesSortedByStart(): Match[]:获取按开始时间排序的比赛列表。getFirstMatch()/getLastMatch():获取第一场和最后一场比赛。getMatchAt(unixSec: number):获取在指定时间点(Unix 秒)正在进行的比赛。getCurrentMatch(nowSec?):获取当前时间正在进行的比赛。getNextMatch(nowSec?):获取当前时间之后的下一场比赛。getCurrentMatchIndex(nowSec?):获取当前比赛在赛程中的索引。getMatchMapByIndex(index: number):根据赛程索引获取比赛地图。getCurrentMatchMap(nowSec?):获取当前比赛的地图信息。getCurrentMatchDurationSec(nowSec?):获取当前比赛已经进行的时长(秒)。getTimeToNextMatchSec(nowSec?):获取距离下一场比赛开始还有多少秒。getCurrentMatchProgress(nowSec?):以0-1的小数形式,估算当前比赛的进度(基于下一场比赛的开始时间)。getCountdownToNextMatch(nowSec?):获取距离下一场比赛开始的倒计时(秒)。
队伍/玩家便捷
getTeamById(id)/getTeamByName(name):通过队伍 ID 或名称查找并返回队伍对象。getTeamPlayers(teamId)/getTeamPlayerIds(teamId):获取指定队伍的所有队员(PlayerRef[])或队员 ID 列表(number[])。getAllPlayerIdsFromTeams()/getAllPlayerRefsFromTeams()/getAllPlayers():获取所有队伍的所有队员 ID 列表、队员引用对象列表或队员引用对象列表(getAllPlayers是getAllPlayerRefsFromTeams的别名)。getMatchTeams(match)/getMatchPlayers(match):获取指定比赛的参赛队伍或所有参赛队员。getCurrentTeams(nowSec?):获取当前比赛的两个参赛队伍(按队伍名称匹配Team对象,可能返回undefined)。getCurrentMatchPlayerRefs(nowSec?):获取当前比赛所有在场玩家的PlayerRef列表。getCurrentMatchTeamsRefs(nowSec?):获取当前比赛按阵营(teamA,teamB)划分的在场玩家PlayerRef列表。isPlayerInCurrentMatch(playerId, nowSec?):判断指定 ID 的玩家当前是否在场比赛。getTeamByPlayerId(playerId)/getPlayerTeamId(playerId):根据玩家 ID 查找其所在的队伍对象或队伍 ID。isPlayerInTeam(teamId, playerId):判断指定玩家是否属于指定队伍。getLineupDiffForTeam(teamId, nowSec?):比较指定队伍的配置阵容与当前实际上场阵容的差异。onStageButNotInTeam: 返回在场但未在队伍配置中的玩家。inTeamButNotOnStage: 返回在队伍配置中但未上场的玩家。
客户端/视图辅助
getScreenType(commentatorsEntity: GamePlayerEntity): 'live_mini' | 'live' | undefined- 功能:从解说员实体的 URL 参数中,解析并获取当前客户端的界面类型。
- 参数:
commentatorsEntity: GamePlayerEntity- 解说员的玩家实体对象。 - 返回:
'live_mini': 小窗副屏直播模式。'live': 大窗主屏直播模式。undefined: 未指定或无法识别。
- 用途:用于根据启动参数,在客户端展现不同的 UI 布局。
getPlayerUiHidden(entity: GamePlayerEntity): boolean- 功能:从玩家实体的 URL 参数中,判断是否需要隐藏游戏内 UI。
- 参数:
entity: GamePlayerEntity- 玩家实体对象。 - 返回:
true表示需要隐藏 UI,false表示正常显示。 - 用途:用于实现“导演”或“观察者”模式,提供一个干净的无 UI 画面。
玩家引用
getPlayerRefById(playerId, nowSec?): 根据玩家 ID 获取其在当前比赛中的引用对象(PlayerRef)。若玩家不在当前比赛,返回undefined。
历史与即将开始
getHistory()/getUpcoming(): 获取原始的“历史活动”和“即将开始”的活动列表。getHistorySortedByStart()/getUpcomingSortedByStart(): 获取按开始时间排序的“历史活动”和“即将开始”的活动列表。
序列化
toJSON(): LivePayload: 返回最新的原始数据负载对象(LivePayload),方便进行序列化(如JSON.stringify)或传递。
类型(来自 server/src/lib/types.ts)
PlayerRef:{ id: number }Team:{ id; name; logo; players: PlayerRef[] }MatchTeam:{ name; logo; players }Match:{ startTime; teamA: MatchTeam; teamB: MatchTeam }MatchMap:{ contentId; name; preview }BracketTeam:{ name; logo }BracketRound:{ title; teams: BracketTeam[] }Bracket:{ stages: string[]; rounds: BracketRound[] }HistoryItem/UpcomingItem:{ title; cover; startTime; url }GameCfg: 包含logo,teams,matches,matchMaps,commentators,operators,bracketLivePayload:- 核心:
type, env, title, description, roomId, startTime, endTime, cover - 扩展:
gameCfg?: GameCfg, history?: HistoryItem[], upcoming?: UpcomingItem[]
- 核心:
LiveUpdater 相关类型
LiveUpdatePlayer:{ id; score?; hp?; kda? }可选实时字段由数据上报方自行决定。LiveUpdateSide:{ score; players: LiveUpdatePlayer[] }LiveUpdatePayload:{ startTime; teamA; teamB; highlight?; danmaku? }LiveUpdatePayloadArray:LiveUpdatePayload[]这些类型已集中在server/src/lib/types.ts并由server/src/App.ts统一导出。
高光/弹幕类型要点:
LiveUpdateHighlight:reason: string高光原因/提示teamNames?: string[]关联队伍名称(与MatchTeam.name对齐)playerIds?: number[]关联选手immediate?: boolean平台是否立刻放大 live_mini
LiveDanmaku:text: string文本内容
LiveUpdater API(上报器)
new LiveUpdater(opts)- opts.key: string(必填)用于后端存储键名
- opts.endpoint?: string 默认
https://api.box3lab.com/set_redis_value - opts.headers?: Record<string, string>
- opts.maxRetries?: number 默认 0
- opts.retryDelayMs?: number 默认 500
- 内置提交节流:两次提交至少间隔 10ms
static buildPayloadFromMatch(match, scores?, playerExtras?) => LiveUpdatePayload- 从
Match构建可提交的载荷(不发送)
- 从
pushFromMatch(match, scores, playerExtras?) => Promise<boolean>- 将单场加入暂存并提交。若之前已提交过历史场次,会自动与历史合并后一起提交
高光与弹幕(即时接口)
pushHighlightNow(match, highlight) => Promise<boolean>- 立刻上报“单一高光”。平台可据此放大 live_mini 等。
- 参数
highlight: LiveUpdateHighlight,示例见下。
stopHighlightNow(match) => Promise<boolean>- 立刻取消当前高光(置空并上报)。
pushDanmakuNow(match, danmaku) => Promise<boolean>- 立刻发送一条弹幕,平台侧会展示该弹幕。
示例:
// 触发高光
await updater.pushHighlightNow(match, {
reason: 'ACE',
teamNames: ['Team A'],
playerIds: [12345],
immediate: true,
});
// 立刻取消高光
await updater.stopHighlightNow(match);
// 发送弹幕
await updater.pushDanmakuNow(match, {
text: '加油!稳住别浪!',
});实用建议
- 做快照或统计前建议
await refreshNow()确保数据最新 - 本地调试可
await useTestData(true)+setNowSecOverride() - 上线前请确保
await useTestData(false)
示例代码
server/src/examples/pushCurrentMatchDemo.ts- 最简示例:获取当前场次并上报比分
server/src/examples/pushPlayerExtrasDemo.ts- 为当前场次上报玩家扩展字段(例如 score/hp/kda)
server/src/examples/pushMultipleMatchesDemo.ts- 连续覆盖多场(历史 + 当前),第二次提交自动把两场一起提交
server/src/examples/pushDryRunDemo.ts- Dry-Run:仅构造并打印 payload,便于联调校验
server/src/examples/highlightDanmakuDemo.ts- 触发高光/弹幕
获取已上报的数据(查询接口)
- 平台查询接口(GET):
https://api.box3lab.com/get_redis_value?key=<你的key> - 例如本仓库示例使用的 key:
demo_player_extras
