Skip to content

Commit

Permalink
Better support for tracking session private and public slots
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianCassar committed Jul 11, 2024
1 parent 3bd9c6c commit 815b8cb
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,12 @@ export class AggregateSessionCommandHandler

index = titles['Titles'].length - 1;
}
const publicSlots = session.openPublicSlots + session.filledPublicSlots;
const privateSlots =
session.openPrivateSlots + session.filledPrivateSlots;

const data = {
mediaId: session.mediaId,
version: session.version,
players: session.players.length,
total: publicSlots + privateSlots,
players: session.players.size,
total: session.totalSlots,
};

titles['Titles'][index]['sessions'].push(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class JoinSessionCommandHandler
}

session.join({
xuids: command.xuids,
members: command.members,
});

await this.repository.save(session);
Expand Down
2 changes: 1 addition & 1 deletion src/application/commands/JoinSessionCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ export class JoinSessionCommand {
constructor(
public readonly titleId: TitleId,
public readonly sessionId: SessionId,
public readonly xuids: Xuid[],
public readonly members: Map<Xuid, boolean>,
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class FindLeaderboardsQueryHandler

leaderboardResponse.players.push({
xuid: player.value,
gamertag: user?.gamertag?.value ? user.gamertag.value : "",
gamertag: user?.gamertag?.value ? user.gamertag.value : '',
stats,
});
}),
Expand Down
146 changes: 126 additions & 20 deletions src/domain/aggregates/Session.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ConsoleLogger } from '@nestjs/common';
import IpAddress from '../value-objects/IpAddress';
import MacAddress from '../value-objects/MacAddress';
import SessionFlags from '../value-objects/SessionFlags';
Expand All @@ -17,7 +18,7 @@ interface SessionProps {
publicSlotsCount: number;
privateSlotsCount: number;
port: number;
players: Xuid[];
players: Map<string, boolean>;
deleted: boolean;
context: Map<string, number>;
migration?: SessionId;
Expand Down Expand Up @@ -55,7 +56,7 @@ interface ContextProps {
}

interface JoinProps {
xuids: Xuid[];
members: Map<Xuid, boolean>;
}

interface LeaveProps {
Expand All @@ -65,20 +66,42 @@ interface LeaveProps {
export default class Session {
private readonly props: SessionProps;

private _availablePublicSlots: number = 0;
private _availablePrivateSlots: number = 0;
private _logger: ConsoleLogger = new ConsoleLogger('Session');

public constructor(props: SessionProps) {
this.props = props;

// Set available slots
const players = Array.from(this.players.values());

const num_private_slots = players.filter((value) => value === true).length;
const num_public_slots = players.filter((value) => value === false).length;

this._availablePrivateSlots = Math.max(
0,
this.privateSlotsCount - num_private_slots,
);

this._availablePublicSlots = Math.max(
0,
this.publicSlotsCount - num_public_slots,
);

this._logger.setContext(`Session - ${props.id.value.toUpperCase()}`);
}

public static create(props: CreateProps) {
return new Session({
...props,
players: [],
players: new Map<string, boolean>(),
deleted: false,
context: new Map<string, number>(),
});
}

static GenerateSessionId() {
public static GenerateSessionId() {
const rnd_value = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);

const session_id_value =
Expand All @@ -103,6 +126,9 @@ export default class Session {

props.session.props.migration = newSession.id;

newSession.availablePrivateSlots = props.session.availablePrivateSlots;
newSession.availablePublicSlots = props.session.availablePublicSlots;

return newSession;
}

Expand All @@ -114,23 +140,92 @@ export default class Session {

public modify(props: ModifyProps) {
this.props.flags = props.flags;

const num_private_slots: number = Math.max(
0,
this.props.privateSlotsCount - this._availablePrivateSlots,
);

const num_public_slots: number = Math.max(
0,
this.props.publicSlotsCount - this._availablePublicSlots,
);

this.props.privateSlotsCount = props.privateSlotsCount;
this.props.publicSlotsCount = props.publicSlotsCount;

// Update available slots
this._availablePrivateSlots = Math.max(
0,
this.props.privateSlotsCount - num_private_slots,
);

this._availablePublicSlots = Math.max(
0,
this.props.publicSlotsCount - num_public_slots,
);
}

public join(props: JoinProps) {
this.props.players.push(...props.xuids);

const xuidValues = this.props.players.map((xuid) => xuid.value);
const distinctXuidValues = [...new Set(xuidValues)];
this.props.players = distinctXuidValues.map((xuid) => new Xuid(xuid));
props.members.forEach((IsPrivate: boolean, xuid: Xuid) => {
this.players.set(xuid.value, IsPrivate);

if (IsPrivate) {
this._availablePrivateSlots = Math.max(
0,
this._availablePrivateSlots - 1,
);
} else {
this._availablePublicSlots = Math.max(
0,
this._availablePublicSlots - 1,
);
}

this._logger.verbose(
`Player Joining:: XUID: ${xuid.value} IsPrivate: ${IsPrivate ? 'true' : 'false'}`,
);

this._logger.verbose(
`AvailablePrivateSlots: ${this.availablePrivateSlots}`,
);

this._logger.verbose(
`AvailablePublicSlots: ${this.availablePublicSlots}`,
);
});
}

public leave(props: LeaveProps) {
const xuidValues = props.xuids.map((xuid) => xuid.value);
this.props.players = this.props.players.filter(
(player) => !xuidValues.includes(player.value),
);
for (const xuid of Array.from(props.xuids)) {
const IsPrivate: boolean = this.players[xuid.value];

this.players.delete(xuid.value);

if (IsPrivate) {
this._availablePrivateSlots = Math.min(
this.privateSlotsCount,
this._availablePrivateSlots + 1,
);
} else {
this._availablePublicSlots = Math.min(
this.publicSlotsCount,
this._availablePublicSlots + 1,
);
}

this._logger.verbose(
`Player Leaving:: XUID: ${xuid.value} IsPrivate: ${IsPrivate ? 'true' : 'false'}`,
);

this._logger.verbose(
`AvailablePrivateSlots: ${this.availablePrivateSlots}`,
);

this._logger.verbose(
`AvailablePublicSlots: ${this.availablePublicSlots}`,
);
}
}

public delete() {
Expand Down Expand Up @@ -173,21 +268,32 @@ export default class Session {
return this.props.privateSlotsCount;
}

get openPublicSlots() {
return this.publicSlotsCount - this.players.length;
get availablePublicSlots() {
return this._availablePublicSlots;
}

set availablePublicSlots(publicSlots: number) {
this._availablePublicSlots = Math.max(0, publicSlots);
}

get openPrivateSlots() {
// TODO: Implement
return this.privateSlotsCount;
get availablePrivateSlots() {
return this._availablePrivateSlots;
}

set availablePrivateSlots(privateSlots: number) {
this._availablePrivateSlots = Math.max(0, privateSlots);
}

get filledPublicSlots() {
return this.publicSlotsCount - this.openPublicSlots;
return this.publicSlotsCount - this.availablePublicSlots;
}

get filledPrivateSlots() {
return this.privateSlotsCount - this.openPrivateSlots;
return this.privateSlotsCount - this.availablePrivateSlots;
}

get totalSlots() {
return this.publicSlotsCount + this.privateSlotsCount;
}

get macAddress() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { ConsoleLogger, Injectable } from '@nestjs/common';
import TitleId from 'src/domain/value-objects/TitleId';
import IpAddress from 'src/domain/value-objects/IpAddress';
import SessionFlags from 'src/domain/value-objects/SessionFlags';
import Xuid from 'src/domain/value-objects/Xuid';
import MacAddress from 'src/domain/value-objects/MacAddress';
import SessionId from 'src/domain/value-objects/SessionId';

Expand All @@ -25,7 +24,7 @@ export default class SessionDomainMapper {
publicSlotsCount: session.publicSlotsCount,
privateSlotsCount: session.privateSlotsCount,
port: session.port,
players: session.players.map((xuid) => new Xuid(xuid)),
players: session.players,
deleted: session.deleted,
context: session.context,
migration: session.migration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class SessionPersistanceMapper {
advertised: session.flags.isAdvertised,
macAddress: session.macAddress.value,
port: session.port,
players: session.players.map((xuid) => xuid.value),
players: session.players,
deleted: session.deleted,
context: session.context,
migration: session.migration ? session.migration.value : undefined,
Expand Down
2 changes: 1 addition & 1 deletion src/infrastructure/persistance/models/SessionSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class Session {
@Prop({ required: true })
port: number;
@Prop({ required: true })
players: string[];
players: Map<string, boolean>;
@Prop({ required: true, default: false })
deleted: boolean;
@Prop({ required: true })
Expand Down
Loading

0 comments on commit 815b8cb

Please sign in to comment.