todo: QUAL LEADERBAORDS AND SORTING
This commit is contained in:
parent
e9d0305566
commit
02c03e3751
12 changed files with 2581 additions and 108 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
import { TAServerPort, TAServerUrl, authTokenStore, client } from "$lib/stores";
|
import { TAServerPort, TAServerUrl, authTokenStore, client } from "$lib/stores";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
import type { BeatSaverMap } from "$lib/services/beatsaver";
|
||||||
|
|
||||||
export let tournamentGuid: string;
|
export let tournamentGuid: string;
|
||||||
export let poolGuid: string;
|
export let poolGuid: string;
|
||||||
|
|
@ -53,33 +54,6 @@
|
||||||
|
|
||||||
// Playing-specific settings
|
// Playing-specific settings
|
||||||
let disableCustomNotesOnStream = false;
|
let disableCustomNotesOnStream = false;
|
||||||
|
|
||||||
type BeatSaverMap = {
|
|
||||||
id: string;
|
|
||||||
metadata: {
|
|
||||||
songName: string;
|
|
||||||
songAuthorName: string;
|
|
||||||
levelAuthorName: string;
|
|
||||||
songSubName: string;
|
|
||||||
duration: number;
|
|
||||||
bpm: number;
|
|
||||||
};
|
|
||||||
versions: Array<{
|
|
||||||
hash: string;
|
|
||||||
state: string;
|
|
||||||
createdAt: string;
|
|
||||||
downloadURL: string;
|
|
||||||
diffs: Array<{
|
|
||||||
characteristic: string;
|
|
||||||
difficulty: string;
|
|
||||||
maxScore: number;
|
|
||||||
nps: number;
|
|
||||||
}>;
|
|
||||||
coverURL: string;
|
|
||||||
previewURL: string;
|
|
||||||
}>;
|
|
||||||
uploaded: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Beat Saber Modifiers with incompatibility groups
|
// Beat Saber Modifiers with incompatibility groups
|
||||||
interface Modifier {
|
interface Modifier {
|
||||||
|
|
@ -433,7 +407,7 @@
|
||||||
selectedCharacteristic = availableCharacteristics[0] || "";
|
selectedCharacteristic = availableCharacteristics[0] || "";
|
||||||
selectedDifficulty = availableDifficulties[selectedCharacteristic]?.[0] || "";
|
selectedDifficulty = availableDifficulties[selectedCharacteristic]?.[0] || "";
|
||||||
|
|
||||||
mapBeatmapId = `custom_level_${latestVersion.hash}`;
|
mapBeatmapId = `custom_level_${latestVersion.hash.toLocaleUpperCase()}`;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -510,20 +484,25 @@
|
||||||
disableScoresaberSubmission: mode === 'playing' ? disableScoresaberSubmission : false,
|
disableScoresaberSubmission: mode === 'playing' ? disableScoresaberSubmission : false,
|
||||||
showScoreboard: mode === 'playing' ? showScoreboard : false,
|
showScoreboard: mode === 'playing' ? showScoreboard : false,
|
||||||
useSync: false,
|
useSync: false,
|
||||||
target: 0
|
target: 0,
|
||||||
|
playerSettings: {
|
||||||
|
options: 0,
|
||||||
|
playerHeight: 0,
|
||||||
|
sfxVolume: 0,
|
||||||
|
saberTrailIntensity: 0,
|
||||||
|
noteJumpStartBeatOffset: 0,
|
||||||
|
noteJumpFixedDuration: 0,
|
||||||
|
noteJumpDurationTypeSettings: 0,
|
||||||
|
arcVisibilityType: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (map) {
|
if (map) {
|
||||||
// I will need to fix this, for now this is a TA server issue
|
|
||||||
dispatch('mapUpdated', { map: mapData });
|
dispatch('mapUpdated', { map: mapData });
|
||||||
} else {
|
} else {
|
||||||
await client.addTournamentPoolMaps(tournamentGuid, poolGuid, [mapData]);
|
|
||||||
dispatch('mapAdded', { map: mapData });
|
dispatch('mapAdded', { map: mapData });
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (response.type !== Response_ResponseType.Success) {
|
|
||||||
// throw new Error("Failed to save map");
|
|
||||||
// }
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
return dispatch('close');
|
return dispatch('close');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -747,19 +726,7 @@
|
||||||
<h4>Tournament Assistant Settings</h4>
|
<h4>Tournament Assistant Settings</h4>
|
||||||
<p class="section-desc">Configure game behavior options</p>
|
<p class="section-desc">Configure game behavior options</p>
|
||||||
|
|
||||||
<div class="qualifier-options">
|
<div class="qualifier-options">
|
||||||
<div class="qualifier-toggle">
|
|
||||||
<label class="switch-label">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
bind:checked={disableFail}
|
|
||||||
on:change={handleDisableFailChange}
|
|
||||||
/>
|
|
||||||
<span class="switch"></span>
|
|
||||||
<span class="label-text">Disable Fail</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="qualifier-toggle">
|
<div class="qualifier-toggle">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input
|
||||||
|
|
@ -772,6 +739,18 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if mode === 'playing'}
|
{#if mode === 'playing'}
|
||||||
|
<div class="qualifier-toggle">
|
||||||
|
<label class="switch-label">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={disableFail}
|
||||||
|
on:change={handleDisableFailChange}
|
||||||
|
/>
|
||||||
|
<span class="switch"></span>
|
||||||
|
<span class="label-text">Disable Fail</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="qualifier-toggle">
|
<div class="qualifier-toggle">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input
|
||||||
|
|
@ -816,7 +795,6 @@
|
||||||
<span class="switch"></span>
|
<span class="switch"></span>
|
||||||
<span class="label-text">Limit Attempts</span>
|
<span class="label-text">Limit Attempts</span>
|
||||||
</label>
|
</label>
|
||||||
<p class="setting-description">Restrict the number of attempts allowed for this qualifier</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if limitAttemptsEnabled}
|
{#if limitAttemptsEnabled}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
interface BeatSaverMap {
|
export interface BeatSaverMap {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|
@ -58,6 +58,7 @@ interface BeatSaverMap {
|
||||||
}>;
|
}>;
|
||||||
downloadURL: string;
|
downloadURL: string;
|
||||||
previewURL: string;
|
previewURL: string;
|
||||||
|
coverURL: string;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +118,22 @@ export async function fetchMapsByHashesOrKeys(identifiers: string[]): Promise<Be
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process hashes in batches
|
// Process hashes in batches
|
||||||
if (hashes.length > 0) {
|
if (hashes.length == 1) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${BEATSAVER_API_BASE}/maps/hash/${hashes[0]}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`BeatSaver API error for hashes: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
const maps = [data];
|
||||||
|
allMaps.push(...maps);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching hash batch:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
} else if (hashes.length > 0) {
|
||||||
const hashBatches: string[][] = [];
|
const hashBatches: string[][] = [];
|
||||||
for (let i = 0; i < hashes.length; i += BATCH_SIZE) {
|
for (let i = 0; i < hashes.length; i += BATCH_SIZE) {
|
||||||
hashBatches.push(hashes.slice(i, i + BATCH_SIZE));
|
hashBatches.push(hashes.slice(i, i + BATCH_SIZE));
|
||||||
|
|
@ -126,7 +142,7 @@ export async function fetchMapsByHashesOrKeys(identifiers: string[]): Promise<Be
|
||||||
for (const batch of hashBatches) {
|
for (const batch of hashBatches) {
|
||||||
try {
|
try {
|
||||||
const hashesParam = batch.join(',');
|
const hashesParam = batch.join(',');
|
||||||
const response = await fetch(`${BEATSAVER_API_BASE}/maps/hashes/${hashesParam}`);
|
const response = await fetch(`${BEATSAVER_API_BASE}/maps/hash/${hashesParam}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`BeatSaver API error for hashes: ${response.status} ${response.statusText}`);
|
throw new Error(`BeatSaver API error for hashes: ${response.status} ${response.statusText}`);
|
||||||
|
|
|
||||||
|
|
@ -26,5 +26,7 @@ export const TAServerUrl = createPersistedStore('TAServerUrl', "server.tournamen
|
||||||
|
|
||||||
export const TAServerPort = createPersistedStore('TAServerPort', "8676");
|
export const TAServerPort = createPersistedStore('TAServerPort', "8676");
|
||||||
|
|
||||||
|
export const TAServerPlayerPort = createPersistedStore('TAServerPlayerPort', "8675");
|
||||||
|
|
||||||
// In the future, use a store for TAClient, since svelte is neat :)))
|
// In the future, use a store for TAClient, since svelte is neat :)))
|
||||||
export const client = new TAClient();
|
export const client = new TAClient();
|
||||||
|
|
@ -134,11 +134,11 @@
|
||||||
|
|
||||||
<div class="footer-section contact">
|
<div class="footer-section contact">
|
||||||
<h4>Contact</h4>
|
<h4>Contact</h4>
|
||||||
<a href="mailto:support@tournamentassistant.net" class="contact-link">
|
<a href="mailto:support@beatkhana.com" class="contact-link">
|
||||||
<span class="material-icons">email</span>
|
<span class="material-icons">email</span>
|
||||||
support@tournamentassistant.net
|
support@beatkhana.com
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.gg/tournament" class="contact-link">
|
<a href="https://discord.gg/AnkmKk6AD8" class="contact-link">
|
||||||
<span class="material-icons">forum</span>
|
<span class="material-icons">forum</span>
|
||||||
Join our Discord
|
Join our Discord
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-bottom">
|
<div class="footer-bottom">
|
||||||
<div class="copyright">
|
<div class="copyright">
|
||||||
© {new Date().getFullYear()} Tournament Assistant. All rights reserved.
|
© {new Date().getFullYear()} Luna & Moon. All rights reserved.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import Notification from '$lib/components/notifications/Popup.svelte';
|
import Notification from '$lib/components/notifications/Popup.svelte';
|
||||||
import { discordAuthUrl } from '$lib/config.json';
|
import { discordAuthUrl } from '$lib/config.json';
|
||||||
import { discordDataStore, discordTokenStore, authTokenStore, TAServerPort, TAServerUrl, client } from '$lib/stores';
|
import { discordDataStore, discordTokenStore, authTokenStore, TAServerPort, TAServerUrl, client, TAServerPlayerPort } from '$lib/stores';
|
||||||
import { TAClient, Response_ResponseType, Tournament } from 'moons-ta-client';
|
import { TAClient, Response_ResponseType, Tournament } from 'moons-ta-client';
|
||||||
import { bufferToImageUrl } from '$lib/services/taImages';
|
import { bufferToImageUrl } from '$lib/services/taImages';
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
@ -125,13 +125,6 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
// if (client.isConnected == true) {
|
|
||||||
// // Properly disconnect and clean up any listeners
|
|
||||||
// client.disconnect();
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
|
|
||||||
async function fetchTournamentAuthorisedUsers(tournamentGuid: string) {
|
async function fetchTournamentAuthorisedUsers(tournamentGuid: string) {
|
||||||
// Get the authorised users for the tournament
|
// Get the authorised users for the tournament
|
||||||
let authorisedUsers = [];
|
let authorisedUsers = [];
|
||||||
|
|
@ -213,14 +206,7 @@
|
||||||
try {
|
try {
|
||||||
creating = true;
|
creating = true;
|
||||||
|
|
||||||
// Connect to the TA server
|
if(!client.isConnected) return;
|
||||||
const connectResult = await client.connect('server.tournamentassistant.net', '8676');
|
|
||||||
|
|
||||||
if (connectResult.details.oneofKind === "connect" && connectResult.type === Response_ResponseType.Fail) {
|
|
||||||
authError = connectResult.details.connect.message;
|
|
||||||
creating = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the tournament object
|
// Create the tournament object
|
||||||
let tournament: Tournament = {
|
let tournament: Tournament = {
|
||||||
|
|
@ -241,6 +227,12 @@
|
||||||
pools: [],
|
pools: [],
|
||||||
allowUnauthorizedView: true
|
allowUnauthorizedView: true
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
name: `${$TAServerUrl}:${$TAServerPort}`,
|
||||||
|
address: $TAServerUrl,
|
||||||
|
port: $TAServerPlayerPort,
|
||||||
|
websocketPort: $TAServerPort
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert image to Uint8Array if an image was provided
|
// Convert image to Uint8Array if an image was provided
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
import { onMount, onDestroy } from "svelte";
|
import { onMount, onDestroy } from "svelte";
|
||||||
import { bkAPIUrl } from '$lib/config.json';
|
import { bkAPIUrl } from '$lib/config.json';
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import { Match, Tournament, TAClient, Response_ResponseType } from 'moons-ta-client';
|
import { Match, Tournament, TAClient, Response_ResponseType, User, User_PlayStates } from 'moons-ta-client';
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import SideMenu from "$lib/components/menus/SideMenuTournaments.svelte";
|
import SideMenu from "$lib/components/menus/SideMenuTournaments.svelte";
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
|
|
@ -15,25 +15,10 @@
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let error: string | null = null;
|
let error: string | null = null;
|
||||||
let matches: Match[] = [];
|
let matches: Match[] = [];
|
||||||
let availablePlayers: any[] = [];
|
let availablePlayers: User[] = [];
|
||||||
let selectedPlayers: any[] = [];
|
|
||||||
let isCreatingMatch: boolean = false;
|
|
||||||
|
|
||||||
// Store for selected player guids
|
// Store for selected player guids
|
||||||
const selectedPlayerGuids = writable<string[]>([]);
|
const selectedPlayerGuids = writable<string[]>([]);
|
||||||
|
|
||||||
// Player status enum
|
|
||||||
enum PlayerStatus {
|
|
||||||
Downloading = "downloading",
|
|
||||||
SelectingSong = "selecting",
|
|
||||||
Idle = "idle"
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PlayerPlayState {
|
|
||||||
In_Menu = 0,
|
|
||||||
Waiting_For_Coordinator = 1,
|
|
||||||
In_Game = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove 'Bearer ' from the token
|
// Remove 'Bearer ' from the token
|
||||||
if($authTokenStore) {
|
if($authTokenStore) {
|
||||||
|
|
@ -49,13 +34,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return status color based on player status
|
// Return status color based on player status
|
||||||
function getStatusColor(status: PlayerStatus): string {
|
function getStatusColor(status: User_PlayStates): string {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case PlayerStatus.Downloading:
|
case User_PlayStates.InGame:
|
||||||
return "var(--danger-color)";
|
return "var(--danger-color)";
|
||||||
case PlayerStatus.SelectingSong:
|
case User_PlayStates.InMenu:
|
||||||
return "#FCD34D"; // Yellow
|
return "#FCD34D"; // Yellow
|
||||||
case PlayerStatus.Idle:
|
case User_PlayStates.WaitingForCoordinator:
|
||||||
return "#10B981"; // Green
|
return "#10B981"; // Green
|
||||||
default:
|
default:
|
||||||
return "var(--text-secondary)";
|
return "var(--text-secondary)";
|
||||||
|
|
@ -110,6 +95,7 @@
|
||||||
tournament = client.stateManager.getTournament(tournamentGuid);
|
tournament = client.stateManager.getTournament(tournamentGuid);
|
||||||
if(!tournament?.users.some(user => user.guid == client.stateManager.getSelfGuid())) {
|
if(!tournament?.users.some(user => user.guid == client.stateManager.getSelfGuid())) {
|
||||||
const joinResult = await client.joinTournament(tournamentGuid);
|
const joinResult = await client.joinTournament(tournamentGuid);
|
||||||
|
console.log('jointournament', joinResult);
|
||||||
if (joinResult.details.oneofKind !== 'join' || joinResult.type === Response_ResponseType.Fail) {
|
if (joinResult.details.oneofKind !== 'join' || joinResult.type === Response_ResponseType.Fail) {
|
||||||
throw new Error('Could not join tournament');
|
throw new Error('Could not join tournament');
|
||||||
}
|
}
|
||||||
|
|
@ -159,19 +145,46 @@
|
||||||
associatedUsers: $selectedPlayerGuids
|
associatedUsers: $selectedPlayerGuids
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(response)
|
console.log("Match created! Response: ", response);
|
||||||
|
|
||||||
const newMatch = (response as any).details.createMatch.match;
|
const newMatch = (response as any).details.createMatch.match;
|
||||||
|
|
||||||
goto(`/tournaments/${tournamentGuid}/matches/${newMatch.guid}`);
|
goto(`/tournaments/${tournamentGuid}/matches/${newMatch.guid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleUserConnected(params: [User, Tournament]) {
|
||||||
|
if(params[1].guid == tournament?.guid) {
|
||||||
|
availablePlayers.push(params[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUserDisconnected(params: [User, Tournament]) {
|
||||||
|
if(params[1].guid == tournament?.guid) {
|
||||||
|
if(availablePlayers.some(x => x.guid == params[0].guid)) {
|
||||||
|
availablePlayers = availablePlayers.filter(x => x.guid !== params[0].guid);
|
||||||
|
} else {
|
||||||
|
let newMatchObject = matches.find(x => x.associatedUsers.includes(params[0].guid))!;
|
||||||
|
newMatchObject.associatedUsers = newMatchObject.associatedUsers.filter(x => x !== params[0].guid);
|
||||||
|
matches = [
|
||||||
|
...matches.filter(x => x.guid !== newMatchObject.guid),
|
||||||
|
newMatchObject
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDiscordNameBecauseShit(user: User) {
|
||||||
|
return user.discordInfo?.username || "";
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async() => {
|
onMount(async() => {
|
||||||
if ($authTokenStore) {
|
if ($authTokenStore) {
|
||||||
await fetchTournamentData();
|
await fetchTournamentData();
|
||||||
client.stateManager.on('matchCreated', handleMatchCreated);
|
client.stateManager.on('matchCreated', handleMatchCreated);
|
||||||
client.stateManager.on('matchDeleted', handleMatchDeleted);
|
client.stateManager.on('matchDeleted', handleMatchDeleted);
|
||||||
client.stateManager.on('matchUpdated', handleMatchUpdated);
|
client.stateManager.on('matchUpdated', handleMatchUpdated);
|
||||||
|
client.stateManager.on('userConnected', handleUserConnected);
|
||||||
|
client.stateManager.on('userDisconnected', handleUserDisconnected);
|
||||||
} else {
|
} else {
|
||||||
window.location.href = "/discordAuth"
|
window.location.href = "/discordAuth"
|
||||||
}
|
}
|
||||||
|
|
@ -181,6 +194,8 @@
|
||||||
client.stateManager.removeListener('matchUpdated', handleMatchUpdated);
|
client.stateManager.removeListener('matchUpdated', handleMatchUpdated);
|
||||||
client.stateManager.removeListener('matchDeleted', handleMatchDeleted);
|
client.stateManager.removeListener('matchDeleted', handleMatchDeleted);
|
||||||
client.stateManager.removeListener('matchCreated', handleMatchDeleted);
|
client.stateManager.removeListener('matchCreated', handleMatchDeleted);
|
||||||
|
client.stateManager.removeListener('userConnected', handleUserConnected);
|
||||||
|
client.stateManager.removeListener('userDisconnected', handleUserDisconnected);
|
||||||
client.removeListener('createdMatch', handleMatchUpdated)
|
client.removeListener('createdMatch', handleMatchUpdated)
|
||||||
// client.disconnect();
|
// client.disconnect();
|
||||||
});
|
});
|
||||||
|
|
@ -287,8 +302,8 @@
|
||||||
alt="Player"
|
alt="Player"
|
||||||
class="player-avatar">
|
class="player-avatar">
|
||||||
<div class="player-info">
|
<div class="player-info">
|
||||||
<h4>{player.name} ({player.discordInfo.username})</h4>
|
<h4>{player.name} ({getDiscordNameBecauseShit(player)})</h4>
|
||||||
<p>{PlayerPlayState[player.playState]}</p>
|
<p>{User_PlayStates[player.playState]}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -149,16 +149,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleMapUpdated(event: CustomEvent) {
|
async function handleMapUpdated(event: CustomEvent) {
|
||||||
const res = await client.updateTournamentPoolMap(tournamentGuid, poolGuid, event.detail.map);
|
await client.updateTournamentPoolMap(tournamentGuid, poolGuid, event.detail.map);
|
||||||
console.log(res)
|
|
||||||
fetchMapPoolData();
|
fetchMapPoolData();
|
||||||
showSuccessNotification = true;
|
showSuccessNotification = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
showSuccessNotification = false;
|
||||||
|
}, 2500);
|
||||||
successMessage = "Map successfully updated!";
|
successMessage = "Map successfully updated!";
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMapAdded(event: CustomEvent) {
|
async function handleMapAdded(event: CustomEvent) {
|
||||||
|
await client.addTournamentPoolMaps(tournamentGuid, poolGuid, [event.detail.map]);
|
||||||
fetchMapPoolData();
|
fetchMapPoolData();
|
||||||
showSuccessNotification = true;
|
showSuccessNotification = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
showSuccessNotification = false;
|
||||||
|
}, 2500);
|
||||||
successMessage = "Map successfully added!";
|
successMessage = "Map successfully added!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,25 +266,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const response: BeatSaverMap = await data.json();
|
const response: BeatSaverMap = await data.json();
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveModifiersCompact(gameplayModifiers: number): string[] {
|
function getActiveModifiersCompact(gameplayModifiers: number): string[] {
|
||||||
const activeModifiers: string[] = [];
|
const activeModifiers: string[] = [];
|
||||||
|
|
||||||
// Get all numeric enum values and sort them
|
// Get all numeric enum values (powers of 2) and sort them
|
||||||
const values = Object.values(GameplayModifiers_GameOptions)
|
const values = Object.values(GameplayModifiers_GameOptions)
|
||||||
.filter((value): value is number =>
|
.filter((value): value is number =>
|
||||||
typeof value === 'number' &&
|
typeof value === 'number' &&
|
||||||
value !== GameplayModifiers_GameOptions.None
|
value !== GameplayModifiers_GameOptions.None &&
|
||||||
|
value > 0
|
||||||
)
|
)
|
||||||
.sort((a, b) => a - b);
|
.sort((a, b) => a - b);
|
||||||
|
|
||||||
console.log(values)
|
|
||||||
|
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
if (gameplayModifiers & value) {
|
// Use bitwise AND to check if this specific flag is set
|
||||||
|
if ((gameplayModifiers & value) === value) {
|
||||||
const name = modifierNameMap[value];
|
const name = modifierNameMap[value];
|
||||||
if (name && name.trim() !== "") {
|
if (name && name.trim() !== "") {
|
||||||
activeModifiers.push(name);
|
activeModifiers.push(name);
|
||||||
|
|
@ -290,11 +296,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getModifierArray(map: any): string[] {
|
function getModifierArray(map: any): string[] {
|
||||||
if (map.taData.gameplayParameters?.gameplayModifiers.options == 0) {
|
if (map.taData.gameplayParameters?.gameplayModifiers?.options == 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return getActiveModifiersCompact(map.taData.gameplayParameters.gameplayModifiers);
|
return getActiveModifiersCompact(map.taData.gameplayParameters?.gameplayModifiers?.options || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async() => {
|
onMount(async() => {
|
||||||
|
|
@ -414,6 +420,18 @@
|
||||||
{:else}
|
{:else}
|
||||||
<span class="no-modifiers">No modifiers active</span>
|
<span class="no-modifiers">No modifiers active</span>
|
||||||
{/each}
|
{/each}
|
||||||
|
{#if map.taData.gameplayParameters?.disableFail}
|
||||||
|
<span class="modifier-tag">Disable Fail</span>
|
||||||
|
{/if}
|
||||||
|
{#if map.taData.gameplayParameters?.disableCustomNotesOnStream}
|
||||||
|
<span class="modifier-tag">Disable Custom Notes On Stream</span>
|
||||||
|
{/if}
|
||||||
|
{#if map.taData.gameplayParameters?.disablePause}
|
||||||
|
<span class="modifier-tag">Disable Pause</span>
|
||||||
|
{/if}
|
||||||
|
{#if map.taData.gameplayParameters?.disableScoresaberSubmission}
|
||||||
|
<span class="modifier-tag">Disable ScoreSaber Submission</span>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// API functions - implement these based on your TA client
|
|
||||||
async function kickPlayerFromMatch(playerGuid: string) {
|
async function kickPlayerFromMatch(playerGuid: string) {
|
||||||
const response = await client.removeUserFromMatch(tournamentGuid, matchGuid, playerGuid);
|
const response = await client.removeUserFromMatch(tournamentGuid, matchGuid, playerGuid);
|
||||||
console.log('Kicking player:', playerGuid);
|
console.log('Kicking player:', playerGuid);
|
||||||
|
|
@ -280,6 +279,13 @@
|
||||||
console.log('Sending players back to menu');
|
console.log('Sending players back to menu');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleUserDisconnected(params: [User, Tournament]) {
|
||||||
|
if(matchPlayers.some(user => user.guid == params[0].guid)) {
|
||||||
|
console.log("User disconnected from match. User: ", params[0])
|
||||||
|
matchPlayers = matchPlayers.filter(x => x.guid !== params[0].guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async() => {
|
onMount(async() => {
|
||||||
if ($authTokenStore) {
|
if ($authTokenStore) {
|
||||||
// Fetch the match data that we need to display
|
// Fetch the match data that we need to display
|
||||||
|
|
@ -287,6 +293,7 @@
|
||||||
// Using stateManger listen to global changes to our match
|
// Using stateManger listen to global changes to our match
|
||||||
client.stateManager.on('matchDeleted', handleMatchDeleted);
|
client.stateManager.on('matchDeleted', handleMatchDeleted);
|
||||||
client.stateManager.on('matchUpdated', handleMatchUpdated);
|
client.stateManager.on('matchUpdated', handleMatchUpdated);
|
||||||
|
client.stateManager.on('userDisconnected', handleUserDisconnected)
|
||||||
} else {
|
} else {
|
||||||
window.location.href = "/discordAuth"
|
window.location.href = "/discordAuth"
|
||||||
}
|
}
|
||||||
|
|
@ -296,6 +303,7 @@
|
||||||
// Remove the listeners that were added on mount
|
// Remove the listeners that were added on mount
|
||||||
client.stateManager.removeListener('matchUpdated', handleMatchUpdated);
|
client.stateManager.removeListener('matchUpdated', handleMatchUpdated);
|
||||||
client.stateManager.removeListener('matchDeleted', handleMatchDeleted);
|
client.stateManager.removeListener('matchDeleted', handleMatchDeleted);
|
||||||
|
client.stateManager.removeListener('userDisconnected', handleUserDisconnected);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
1100
src/routes/tournaments/[tournamentguid]/qualifiers/+page.svelte
Normal file
1100
src/routes/tournaments/[tournamentguid]/qualifiers/+page.svelte
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,6 @@
|
||||||
|
export function load({ params }: any){
|
||||||
|
return {
|
||||||
|
tournamentGuid: params.tournamentguid,
|
||||||
|
params: params
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,7 @@
|
||||||
|
export function load({ params }: any){
|
||||||
|
return {
|
||||||
|
tournamentGuid: params.tournamentguid,
|
||||||
|
qualifierGuid: params.qualifierGuid,
|
||||||
|
params: params
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue