Instancing (currently unused)

This commit is contained in:
2025-03-25 00:42:27 -04:00
parent ad73736517
commit de3d653446
2 changed files with 100 additions and 9 deletions

View File

@@ -1,5 +1,8 @@
import Logging from "@proxnet/undead-logging";
import Profile from "../profiles.ts";
const log = new Logging("Instances");
enum IntegratedRoomScene {
Calibration = "f5fbd9c9-e853-4036-9d48-5f68e861af04",
DormRoom = "76d98498-60a1-430c-ab76-b54a29b7a163",
@@ -48,7 +51,7 @@ enum IntegratedRoomScene {
DodgeballVR = "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
}
interface RoomInstance {
export interface RoomInstance {
roomInstanceId: number,
roomId: number,
@@ -67,21 +70,98 @@ interface RoomInstance {
}
const instancePlayers: Map<RoomInstance, Set<Profile>> = new Map();
/**
* `Map<roomId (number), RoomInstance>`
*/
const instanceMap: Map<number, Set<RoomInstance>> = new Map();
class InstancesBase {
async #ensureSubSet(roomId: number) {
const subMap = instanceMap.get(roomId);
if (!subMap) instanceMap.set(roomId, new Set());
getAllInstances() {
return new Set([...instanceMap.values()].flatMap(set => [...set]));
}
// get all instances
// get all instances for a room
// do not put instance categorization here (instance searching, or "matchmaking"); put that in MatchmakingBase
getAllRoomInstances(roomId: number) {
let instances = instanceMap.get(roomId);
if (!instances) {
instances = new Set();
instanceMap.set(roomId, instances);
}
return instances;
}
getInstancePlayers(instance: RoomInstance): Set<Profile> {
let players = instancePlayers.get(instance);
if (!players) {
players = new Set();
instancePlayers.set(instance, players);
}
return players;
}
clearEmptyInstances(instances: Set<RoomInstance>, roomId?: number) {
const beforeCount = instances.size;
for (const instance of instances) {
const profiles = this.getInstancePlayers(instance);
if (profiles.size === 0) {
log.i(`Instance ${instance.roomInstanceId} empty, deleting`);
instancePlayers.delete(instance);
this.getAllRoomInstances(instance.roomId).delete(instance);
}
}
const afterCount = instances.size;
log.d(`Cleared ${roomId !== undefined ? `room ${roomId}` : 'all'} empty instances.\n Instances before: ${beforeCount}\n Instances after: ${afterCount}`);
}
clearAllEmptyInstances() {
this.clearEmptyInstances(this.getAllInstances());
}
clearAllRoomEmptyInstances(roomId: number) {
this.clearEmptyInstances(this.getAllRoomInstances(roomId), roomId);
}
updateGlobalInstancesIsFull() {
for (const instance of this.getAllInstances()) {
instance.isFull = this.getInstancePlayers(instance).size >= instance.maxCapacity;
}
}
updateSingleInstanceIsFull(instance: RoomInstance) {
const profiles = this.getInstancePlayers(instance);
if (profiles.size >= instance.maxCapacity) instance.isFull = true;
else instance.isFull = false;
}
instanceCanFitPlayer(instance: RoomInstance) {
return this.getInstancePlayers(instance).size < instance.maxCapacity;
}
// add, remove, check for, get profile(s) in instances
// synchronize profile.#instance with the profile's current instance (profile.setInstance(RoomInstance)?)
setPlayerInstance(player: Profile, instance: RoomInstance) {
const currentInstance = player.getInstance();
if (currentInstance === instance) return;
if (currentInstance) {
this.getInstancePlayers(currentInstance).delete(player);
this.updateSingleInstanceIsFull(currentInstance);
}
if (this.instanceCanFitPlayer(instance)) {
this.getInstancePlayers(instance).add(player);
player.setInstance(instance);
this.updateSingleInstanceIsFull(instance);
} else log.w(`Instance ${instance.roomInstanceId} is full. Cannot add player ${player.getId()}`);
}
playerIsInInstance(player: Profile, instance: RoomInstance) {
const profiles = this.getInstancePlayers(instance);
return profiles.has(player);
}
}

View File

@@ -4,6 +4,7 @@ import { Config } from "../config.ts";
import { AuthType } from "./users.ts";
import * as JsonWebToken from "@gz/jwt";
import { TokenBaseFormat } from "../apiutils.ts";
import { RoomInstance } from "./live/instances.ts";
const config = Config.getConfig();
@@ -180,15 +181,25 @@ class Profile {
#id: number;
#instance: RoomInstance | null = null;
constructor(id: number) {
this.#id = id;
}
setInstance(instance: RoomInstance) {
this.#instance = instance;
}
getInstance() {
return this.#instance;
}
getId() {
return this.#id;
}
async getIsDev() {
async getIsOperator() {
return (await Redis.Database.sismember(Redis.buildKey(Redis.KeyGroups.Operators), this.#id.toString())) >= 1;
}
@@ -203,7 +214,7 @@ class Profile {
const payload: ProfileTokenFormat = {
iss: config.web.publichost,
sub: this.#id,
role: (await this.getIsDev()) ? 'developer' : 'user',
role: (await this.getIsOperator()) ? 'developer' : 'user',
exp: Math.round(Date.now() / 1000) + Math.round(config.auth.timeout * 60 * 60),
typ: AuthType.Game
};