Skip to content

Commit

Permalink
replay recording and uploading, discord webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
dapucita committed Mar 19, 2021
1 parent 2d4d97d commit 7589bab
Show file tree
Hide file tree
Showing 15 changed files with 439 additions and 45 deletions.
9 changes: 9 additions & 0 deletions core/game/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ window.gameRoom = {
_room: window.HBInit(loadedConfig._config)
,config: loadedConfig
,link: ''
,social: {
discordWebhook: {
feed: false
,replayUpload: false
,id: ''
,token: ''
}
}
,stadiumData: {
default: localStorage.getItem('_defaultMap')!
,training: localStorage.getItem('_readyMap')!
Expand Down Expand Up @@ -64,6 +72,7 @@ window.document.title = `Haxbotron ${window.gameRoom.config._RUID}`;
makeRoom();
// ====================================================================================================
// set scheduling timers

var scheduledTimer60 = setInterval(() => {
window.gameRoom._room.sendAnnouncement(LangRes.scheduler.advertise, null, 0x777777, "normal", 0); // advertisement

Expand Down
4 changes: 4 additions & 0 deletions core/game/controller/events/onGameStart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,9 @@ export function onGameStartListener(byPlayer: PlayerObject | null): void {
} else {
window.gameRoom._room.sendAnnouncement(Tst.maketext(LangRes.onStart.stopRecord, placeholderStart), null, 0x00FF00, "normal", 0);
}

// replay record start
window.gameRoom._room.startRecording();

window.gameRoom.logger.i('onGameStart', msg);
}
17 changes: 17 additions & 0 deletions core/game/controller/events/onGameStop.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as Tst from "../Translator";
import * as LangRes from "../../resource/strings";
import { PlayerObject } from "../../model/GameObject/PlayerObject";
import { convertTeamID2Name, TeamID } from "../../model/GameObject/TeamID";
import { recuritBothTeamFully } from "../../model/OperateHelper/Quorum";
Expand Down Expand Up @@ -42,6 +44,21 @@ export function onGameStopListener(byPlayer: PlayerObject): void {
window.gameRoom.ballStack.clear(); // clear the stack.
window.gameRoom.ballStack.possClear(); // clear possession count

// stop replay record and send it
const replay = window.gameRoom._room.stopRecording();

if(replay && window.gameRoom.social.discordWebhook.feed && window.gameRoom.social.discordWebhook.replayUpload && window.gameRoom.social.discordWebhook.id && window.gameRoom.social.discordWebhook.token) {
const placeholder = {
roomName: window.gameRoom.config._config.roomName
,replayDate: Date().toLocaleString()
}

window._feedSocialDiscordWebhook(window.gameRoom.social.discordWebhook.id, window.gameRoom.social.discordWebhook.token, "replay", {
message: Tst.maketext(LangRes.onStop.feedSocialDiscordWebhook.replayMessage, placeholder)
,data: JSON.stringify(Array.from(replay))
});
}

// when auto emcee mode is enabled
if(window.gameRoom.config.rules.autoOperating === true) {
recuritBothTeamFully();
Expand Down
2 changes: 1 addition & 1 deletion core/game/model/RoomObject/RoomObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export interface Room {
Stops the recording previously started with startRecording and returns the replay file contents as a Uint8Array.
Returns null if recording was not started or had already been stopped.
*/
stopRecording(): Uint8Array;
stopRecording(): Uint8Array | null;

/*
Changes the password of the room, if pass is null the password will be cleared.
Expand Down
4 changes: 3 additions & 1 deletion core/game/resource/strings.sample.en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ export const onStart = {
}

export const onStop = {

feedSocialDiscordWebhook: {
replayMessage: '💽 Replay file from {roomName} ({replayDate})'
}
}

export const onVictory = {
Expand Down
4 changes: 3 additions & 1 deletion core/game/resource/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ export const onStart = {
}

export const onStop = {

feedSocialDiscordWebhook: {
replayMessage: '💽 {roomName}의 리플레이 파일 ({replayDate})'
}
}

export const onVictory = {
Expand Down
6 changes: 6 additions & 0 deletions core/lib/browser.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type DiscordWebhookConfig = {
feed: boolean
id: string
token: string
replayUpload: boolean
}
63 changes: 58 additions & 5 deletions core/lib/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import * as dbUtilityInject from "./db.injection";
import { loadStadiumData } from "./stadiumLoader";
import { Server as SIOserver, Socket as SIOsocket } from "socket.io";
import { TeamID } from "../game/model/GameObject/TeamID";
import Discord from 'discord.js';
import { DiscordWebhookConfig } from "./browser.interface";

function typedArrayToBuffer(array: Uint8Array): ArrayBuffer {
return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)
}

/**
* Use this class for control Headless Browser.
Expand Down Expand Up @@ -83,8 +89,11 @@ export class HeadlessBrowser {
* Close given page.
*/
private async closePage(ruid: string) {
await this._PageContainer.get(ruid)?.close();
this._PageContainer.delete(ruid);
await this._PageContainer.get(ruid)?.evaluate(() => {
window.gameRoom._room.stopRecording(); // suspend recording for prevent memory leak
});
await this._PageContainer.get(ruid)?.close(); // close page
this._PageContainer.delete(ruid); // delete from container
}

/**
Expand Down Expand Up @@ -164,19 +173,39 @@ export class HeadlessBrowser {
page.addListener('_SIO.StatusChange', (event: any) => {
this._SIOserver?.sockets.emit('statuschange', { ruid: ruid, playerID: event.playerID });
});
page.addListener('_SOCIAL.DiscordWebhook', (event: any) => {
const webhookClient = new Discord.WebhookClient(event.id, event.token);

switch (event.type as string) {
case "replay": {
const bufferData = Buffer.from(JSON.parse(event.content.data));
const date = Date.now().toLocaleString();
const attachment = new Discord.MessageAttachment(
bufferData
, `${date}.hbr2`);
webhookClient.send(event.content.message, {
files: [attachment],
});
break;
}
}
});
// ================================================================================

// ================================================================================
// inject some functions ==========================================================
await page.exposeFunction('_emitSIOLogEvent', (origin: string, type: string, message: string) => {
page.emit('_SIO.Log', { origin: origin, type: type, message: message });
})
});
await page.exposeFunction('_emitSIOPlayerInOutEvent', (playerID: number) => {
page.emit('_SIO.InOut', { playerID: playerID });
})
});
await page.exposeFunction('_emitSIOPlayerStatusChangeEvent', (playerID: number) => {
page.emit('_SIO.StatusChange', { playerID: playerID });
})
});
await page.exposeFunction('_feedSocialDiscordWebhook', (id: string, token: string, type: string, content: any) => {
page.emit('_SOCIAL.DiscordWebhook', { id: id, token: token, type: type, content: content });
});

// inject functions for CRUD with DB Server ====================================
await page.exposeFunction('_createSuperadminDB', dbUtilityInject.createSuperadminDB);
Expand Down Expand Up @@ -616,4 +645,28 @@ export class HeadlessBrowser {
window.gameRoom.logger.i('system', `[TeamColour] New team colour is set for Team ${team}.`);
}, team, angle, textColour, teamColour1, teamColour2, teamColour3);
}

/**
* Get discord webhook configuration
* @param ruid ruid Game room's UID
* @returns discord webhook configuration
*/
public async getDiscordWebhookConfig(ruid: string) {
return await this._PageContainer.get(ruid)!.evaluate(() => {
return window.gameRoom.social.discordWebhook as DiscordWebhookConfig;
});
}

/**
* Set discord webhook configuration
* @param ruid ruid Game room's UID
* @param config discord webhook configuration
*/
public async setDiscordWebhookConfig(ruid: string, config: DiscordWebhookConfig) {
await this._PageContainer.get(ruid)!.evaluate((config: DiscordWebhookConfig) => {
window.gameRoom.social.discordWebhook = config;
}, config);
}
}


78 changes: 77 additions & 1 deletion core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"axios": "^0.21.1",
"bcrypt": "^5.0.0",
"cookie": "^0.4.1",
"discord.js": "^12.5.1",
"dotenv": "^8.2.0",
"joi": "^17.3.0",
"jsonwebtoken": "^8.5.1",
Expand Down
Loading

0 comments on commit 7589bab

Please sign in to comment.