(untested) spectator implementation

This commit is contained in:
Holly Stubbs 2022-11-27 17:37:28 +00:00
parent 9f6339ce48
commit 1907e9910d
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
4 changed files with 92 additions and 10 deletions

View file

@ -3,6 +3,7 @@ import { ConsoleHelper } from "../ConsoleHelper";
import { Channel } from "./objects/Channel"; import { Channel } from "./objects/Channel";
import { ChatManager } from "./ChatManager"; import { ChatManager } from "./ChatManager";
import { Database } from "./objects/Database"; import { Database } from "./objects/Database";
import { DataStreamArray } from "./objects/DataStreamArray";
import { LatLng } from "./objects/LatLng"; import { LatLng } from "./objects/LatLng";
import { LoginProcess } from "./LoginProcess"; import { LoginProcess } from "./LoginProcess";
import { Packets } from "./enums/Packets"; import { Packets } from "./enums/Packets";
@ -10,17 +11,15 @@ import { replaceAll } from "./Util";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { RedisClientType, createClient } from "redis"; import { RedisClientType, createClient } from "redis";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { SpectatorManager } from "./SpectatorManager";
import { UserArray } from "./objects/UserArray"; import { UserArray } from "./objects/UserArray";
import { User } from "./objects/User"; import { User } from "./objects/User";
import { DataStreamArray } from "./objects/DataStreamArray";
import { MultiplayerManager } from "./MultiplayerManager"; import { MultiplayerManager } from "./MultiplayerManager";
import { SharedContent } from "./interfaces/SharedContent"; import { SharedContent } from "./interfaces/SharedContent";
const config:Config = JSON.parse(readFileSync("./config.json").toString()) as Config; const config:Config = JSON.parse(readFileSync("./config.json").toString()) as Config;
// TODO: Port osu-packet to TypeScript // TODO: Port osu-packet to TypeScript
const osu = require("osu-packet"); const osu = require("osu-packet");
const sharedContent:any = {}; const sharedContent:any = {};
// NOTE: This function should only be used externaly in Binato.ts and in this file. // NOTE: This function should only be used externaly in Binato.ts and in this file.
export function GetSharedContent() : SharedContent { export function GetSharedContent() : SharedContent {
@ -53,6 +52,8 @@ chatManager.AddChatChannel("japanese", "Talk in exclusively Japanese");
const multiplayerManager:MultiplayerManager = sharedContent.mutiplayerManager = new MultiplayerManager(GetSharedContent()); const multiplayerManager:MultiplayerManager = sharedContent.mutiplayerManager = new MultiplayerManager(GetSharedContent());
const spectatorManager:SpectatorManager = new SpectatorManager(GetSharedContent());
let redisClient:RedisClientType; let redisClient:RedisClientType;
async function subscribeToChannel(channelName:string, callback:(message:string) => void) { async function subscribeToChannel(channelName:string, callback:(message:string) => void) {
@ -97,7 +98,6 @@ import { Logout } from "./packets/Logout";
import { UserPresence } from "./packets/UserPresence"; import { UserPresence } from "./packets/UserPresence";
import { UserStatsRequest } from "./packets/UserStatsRequest"; import { UserStatsRequest } from "./packets/UserStatsRequest";
import { UserPresenceBundle } from "./packets/UserPresenceBundle"; import { UserPresenceBundle } from "./packets/UserPresenceBundle";
import { Match } from "./objects/Match";
// User timeout interval // User timeout interval
setInterval(() => { setInterval(() => {
@ -171,15 +171,15 @@ export async function HandleRequest(req:Request, res:Response, packet:Buffer) {
break; break;
case Packets.Client_StartSpectating: case Packets.Client_StartSpectating:
//Spectator.startSpectatingUser(PacketUser, CurrentPacket.data); spectatorManager.startSpectating(PacketUser, CurrentPacket.data);
break; break;
case Packets.Client_SpectateFrames: case Packets.Client_SpectateFrames:
//Spectator.sendSpectatorFrames(PacketUser, CurrentPacket.data); spectatorManager.spectatorFrames(PacketUser, CurrentPacket.data);
break; break;
case Packets.Client_StopSpectating: case Packets.Client_StopSpectating:
//Spectator.stopSpectatingUser(PacketUser); spectatorManager.stopSpectating(PacketUser);
break; break;
case Packets.Client_SendPrivateMessage: case Packets.Client_SendPrivateMessage:

View file

@ -0,0 +1,79 @@
import { DataStream } from "./objects/DataStream";
import { SharedContent } from "./interfaces/SharedContent";
import { User } from "./objects/User";
const osu = require("osu-packet");
export class SpectatorManager {
private sharedContent:SharedContent;
public constructor(sharedContent:SharedContent) {
this.sharedContent = sharedContent;
}
public startSpectating(user:User, userIdToSpectate:number) {
const userToSpectate = this.sharedContent.users.getById(userIdToSpectate);
if (userToSpectate === undefined) {
return;
}
// Use existing or create spectator stream
let spectateStream:DataStream;
if (userToSpectate.spectatorStream === undefined) {
user.spectatorStream = spectateStream = userToSpectate.spectatorStream = this.sharedContent.streams.CreateStream(`spectator:${userToSpectate.username}`);
} else {
user.spectatorStream = spectateStream = userToSpectate.spectatorStream;
}
user.spectatingUser = userToSpectate;
let osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.SpectatorJoined(user.id);
userToSpectate.addActionToQueue(osuPacketWriter.toBuffer);
osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.FellowSpectatorJoined(user.id);
spectateStream.Send(osuPacketWriter.toBuffer);
}
// TODO: Interface for spectateFrameData
public spectatorFrames(user:User, spectateFrameData:any) {
if (user.spectatorStream === undefined) {
return;
}
const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.SpectateFrames(spectateFrameData);
user.spectatorStream.Send(osuPacketWriter.toBuffer);
}
public stopSpectating(user:User) {
if (user.spectatingUser === undefined || user.spectatorStream === undefined) {
return;
}
const spectatedUser = user.spectatingUser;
let osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.SpectatorLeft(user.id);
spectatedUser.addActionToQueue(osuPacketWriter.toBuffer);
const stream = user.spectatorStream;
stream.RemoveUser(user);
user.spectatorStream = undefined;
user.spectatingUser = undefined;
if (stream.IsActive) {
osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.FellowSpectatorLeft(user.id);
stream.Send(osuPacketWriter.toBuffer);
} else {
spectatedUser.spectatorStream = undefined;
}
}
}

View file

@ -18,6 +18,10 @@ export class DataStream {
this.removeWhenEmpty = removeWhenEmpty; this.removeWhenEmpty = removeWhenEmpty;
} }
public get IsActive() : boolean {
return this.inactive;
}
private checkInactive() { private checkInactive() {
if (this.inactive) { if (this.inactive) {
throw `Stream ${this.name} is inactive (deleted) and cannot be used here.`; throw `Stream ${this.name} is inactive (deleted) and cannot be used here.`;

View file

@ -26,13 +26,12 @@ export class User {
// Binato data // Binato data
public rankingMode:RankingModes = RankingModes.PP; public rankingMode:RankingModes = RankingModes.PP;
public spectatorStream:DataStream | null = null; public spectatorStream?:DataStream;
public spectatingUser?:User;
// osu! data // osu! data
public playMode:number = 0; public playMode:number = 0;
public countryID:number = 0; public countryID:number = 0;
//public spectators:Array; // TODO: Figure out if this was ever needed
public spectating:number = -1;
public location:LatLng = new LatLng(0, 0); public location:LatLng = new LatLng(0, 0);
public joinedChannels:Array<string> = new Array<string>(); public joinedChannels:Array<string> = new Array<string>();