(untested) spectator implementation
This commit is contained in:
parent
9f6339ce48
commit
1907e9910d
4 changed files with 92 additions and 10 deletions
|
@ -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:
|
||||||
|
|
79
server/SpectatorManager.ts
Normal file
79
server/SpectatorManager.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.`;
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue