make work

This commit is contained in:
Luna 2025-10-18 18:31:15 +02:00
parent 67b09a864a
commit a0c3d54713
14 changed files with 325 additions and 68 deletions

12
package-lock.json generated
View file

@ -715,6 +715,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -1033,6 +1034,7 @@
"integrity": "sha512-4XyY1SCB/Eyz8E9G7SEBKViysYwVtDftuA7kyQ5bmuFNPWC1KZC4988rMvaJxhH2BbCTsbLPjNOZwiEGXt8/2g==", "integrity": "sha512-4XyY1SCB/Eyz8E9G7SEBKViysYwVtDftuA7kyQ5bmuFNPWC1KZC4988rMvaJxhH2BbCTsbLPjNOZwiEGXt8/2g==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"cookie": "^0.6.0", "cookie": "^0.6.0",
@ -1064,6 +1066,7 @@
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz",
"integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
"debug": "^4.3.4", "debug": "^4.3.4",
@ -1598,6 +1601,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz",
"integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==",
"devOptional": true, "devOptional": true,
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~6.19.2" "undici-types": "~6.19.2"
} }
@ -1812,6 +1816,7 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001669", "caniuse-lite": "^1.0.30001669",
"electron-to-chromium": "^1.5.41", "electron-to-chromium": "^1.5.41",
@ -2338,6 +2343,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC", "license": "ISC",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }
@ -6373,6 +6379,7 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@ -6433,6 +6440,7 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"lilconfig": "^3.0.0", "lilconfig": "^3.0.0",
"yaml": "^2.3.4" "yaml": "^2.3.4"
@ -6611,6 +6619,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/estree": "1.0.6" "@types/estree": "1.0.6"
}, },
@ -6997,6 +7006,7 @@
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz",
"integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.1", "@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/sourcemap-codec": "^1.4.15",
@ -7234,6 +7244,7 @@
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -7307,6 +7318,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.43", "postcss": "^8.4.43",

View file

@ -38,7 +38,7 @@ The connectResult has the following schema:
respondingToPacketId: 'Packet-Guid', respondingToPacketId: 'Packet-Guid',
details: { details: {
oneofKind: 'connect', oneofKind: 'connect',
connect: { serverVersion: 118, message: '', reason: 0, state: [Object] } connect: { serverVersion: 1220, message: '', reason: 0, state: Object }
} }
} }
``` ```
@ -52,8 +52,8 @@ The state object looks as follows:
users: [], users: [],
matches: [], matches: [],
qualifiers: [], qualifiers: [],
settings: [Object], settings: Object,
server: [Object] server: Object
} }
], ],
knownServers: [ knownServers: [
@ -68,4 +68,4 @@ The state object looks as follows:
``` ```
`connectResult.details.connect.knownServers` includes all of the main TA servers which are currently running. In the future it may be that BSWC or some large tournaments opt to run their own TA servers, however this is highly unlikely as it is not the direction TA is going. `connectResult.details.connect.knownServers` includes all of the main TA servers which are currently running. In the future it may be that BSWC or some large tournaments opt to run their own TA servers, however this is highly unlikely as it is not the direction TA is going.
`connectResult.details.connect.tournaments` is an array of all of the tournaments on the server which you just connected to. It includes the `guid` of the tournament, which we will use to join it and perform other operations. It also includes the `users` array which is going to play a crucial role in determining players etc. Note that the `users` array includes ALL users. It includes bot users, coordinators, players in matches, players in the lobby, anyone connected. We will get to the other properties soon, however it is best if you jump to the section with the tournament proto model. `connectResult.details.connect.tournaments` is an array of all of the tournaments on the server which you just connected to. It includes the `guid` of the tournament, which we will use to join it and perform other operations. It also includes the `users` array which is going to play a crucial role in determining players etc. Note that the `users` array includes ALL users. It includes bot users, coordinators, players in matches, players in the lobby, and anyone connected. We will get to the other properties soon, however it is best if you jump to the section with the tournament proto model.

View file

@ -4,7 +4,7 @@
- The connection to the TA Core Server is a websocket connection. If you wish, you can opt not to use the provided client, however it is strongly advised against due to serialisation. - The connection to the TA Core Server is a websocket connection. If you wish, you can opt not to use the provided client, however it is strongly advised against due to serialisation.
- Beware that the coordinator(or the client in other words) connects to a different port on the server than the player playing, hence it is not possible to directly listen to packets from players. - Beware that the coordinator(or the client in other words) connects to a different port on the server than the player playing, hence it is not possible to directly listen to packets from players. (Unless a feature uses this, more on this later, especially during the handlin of realtime-scores)
- TournamentAssistant does not *yet* support hosting your own Core Server in order to reduce complications for players and developers alike. - TournamentAssistant does not *yet* support hosting your own Core Server in order to reduce complications for players and developers alike.

View file

@ -1,5 +1,5 @@
# An Introduction to the StateManager # An Introduction to the StateManager
The `client.stateManager`(`stateManager` for short), is the simple way of communicating and syncing with the state on the `CoreServer`. If you alrady understand what 'state-based' means, then you may skip this page. The `client.stateManager`(`stateManager` for short), is the simple way of communicating and syncing with the state on the `CoreServer`. If you already understand what 'state-based' means, then you may skip this page.
The `stateManager` is the way you would fetch tournaments, get matches, or do anything related to getting specific data that does not require a database query. It is best if you are familiar with what methods it has and how you can use them. The `stateManager` is the way you would fetch tournaments, get matches, or do anything related to getting specific data that does not require a database query. It is best if you are familiar with what methods it has and how you can use them.

View file

@ -1,6 +1,13 @@
# The taClient.addAuthorizedUser() method # The taClient.addAuthorizedUser() method
This documents the `taClient.addAuthorizedUser()` method. This documents the `taClient.addAuthorizedUser()` method.
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Async:</strong> This is a method you would want to use await with
</div>
</div>
This method has input parameters. The function could easily be defined as: This method has input parameters. The function could easily be defined as:
```ts ```ts
async function addAuthorizedUser(tournamentId: string, discordId: string, roleIds: string[]): Promise<Response> { async function addAuthorizedUser(tournamentId: string, discordId: string, roleIds: string[]): Promise<Response> {
@ -14,9 +21,6 @@ const response: Response = taClient.addAuthorizedUser(tournamentGuid, userDiscor
The `response` variable from above will actually be a 'mashup' of two types. Firstly, the standard `Response` type. Secondly the `Response_AddAuthorizedUser`. Find the custom response object below. The `response` variable from above will actually be a 'mashup' of two types. Firstly, the standard `Response` type. Secondly the `Response_AddAuthorizedUser`. Find the custom response object below.
- For `Response` please find documentation at [Modals -> Response](/documentation#Modals/4-Response)
- For `Response_AddAuthorizedUser` please find documentation at [Modals -> Response_AddAuthorizedUser](/documentation#Modals/4-Response_AddAuthorizedUser).
```js ```js
{ {
details: { details: {
@ -27,6 +31,8 @@ The `response` variable from above will actually be a 'mashup' of two types. Fir
type: Response_ResponseType type: Response_ResponseType
} }
``` ```
- For `Response` please find documentation at [Modals -> Response](/documentation#Modals/4-Response)
- For `Response_AddAuthorizedUser` please find documentation at [Modals -> Response_AddAuthorizedUser](/documentation#Modals/4-Response_AddAuthorizedUser).
<div class="info-box"> <div class="info-box">
<span class="material-icons">info</span> <span class="material-icons">info</span>
@ -36,7 +42,24 @@ The `response` variable from above will actually be a 'mashup' of two types. Fir
</div> </div>
```ts ```ts
ts example here // This is some base data about the user passed on from the popup where we add the authorised user
const userData = event.detail;
// Log the user data that is passed on
console.log('Adding user:', userData);
try {
// Try to add the authorised user given their discord / platform id to the tournament with the selected roles
let addAuthorizedUserResult = await client.addAuthorizedUser(tournamentGuid, userData.discordId, userData.roleIds);
// If successful, add to the authorizedUsers array
if (addAuthorizedUserResult.type === Response_ResponseType.Success) {
authorizedUsers = [...authorizedUsers, userData];
}
} catch (err) {
console.error('Error adding user:', err);
// If there is an error, display it and tell the user to show us the data passed on from the popup.
error = "Failed to add user, please view console, screenshot it and send it to serverbp or matrikmoon on Discord.";
}
``` ```
<div class="info-box"> <div class="info-box">
<span class="material-icons">info</span> <span class="material-icons">info</span>

View file

@ -0,0 +1,72 @@
# The taClient.addQualifierMaps() method
This documents the `taClient.addQualifierMaps()` method.
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Async:</strong> This is a method you would want to use await with
</div>
</div>
This method has input parameters. The function could easily be defined as:
```ts
async function addQualifierMaps(tournamentId: string, qualifierId: string, maps: Map[]): Promise<Response> {
// backend logic
}
```
`tournamentId` and `qualifierId` both refer to the guid of the object. In this case they are the `tournament.guid` and the `qualifierEvent.guid`.
## General usage:
```ts
const response: Response = taClient.addQualifierMaps(tournamentGuid, qualifierEventGuid, [map1, map2]);
```
- For the `Map` modal please find documentation at [Modals -> Response](/documentation#Modals/4-Map)
- For `Response` please find documentation at [Modals -> Response](/documentation#Modals/4-Response)
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Note:</strong> Some parameters do not actually have to be provided, but for a complete object to exist you must give it some placeholder value.
</div>
</div>
A the following properties for the maps may be left empty or as a placeholder value:
- `map.guid`: may be left as `""`
- `map.gameplayParameters.playerSettings`: may be left as an empty [PlayerSpecificSettings](/documentation#Modals/4-PlayerSpecificSettings) object
- for qualifier maps `map.disableCustomNotesOnStream` and `map.useSync` will not have any effect on gameplay, hence they can be left as a boolean value such as `false`
If you have not yet, please read [Client -> Introduction to the Client](/documentation#Client/3-client-intro)
```js
{
details: {
addQualifierMaps: Request_AddQualifierMaps,
oneofKind: 'addQualifierMaps'
},
respondingToPacketId: 'packet-guid-uuidv4',
type: Response_ResponseType
}
```
- For `Request_AddQualifierMaps` please find documentation at [Modals -> Request_AddQualifierMaps](/documentation#Modals/4-Request_AddQualifierMaps).
```ts
// this method is called when the user submits the AddOrEditMapModal.svelte form
async function handleMapAdded(event: CustomEvent) {
// add the single map that the user configured. This includes all settings and data for the map.
await client.addQualifierMaps(tournamentGuid, qualifierGuid, [event.detail.map]);
// a local method to just "refresh" the data on the page for reactivity
fetchQualifierData();
// a horrible example of how to use confirmations and modals
// show the popup for "Successfully added the map!"
modalMessage = `Successfully added the map!`;
modalIcon = 'check';
modalButtons = [];
modalAutoClose = 1;
showGenericModal = true;
}
```
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Example:</strong> This is a direct example from ShyyTAUI. It comes from the page where users edit qualifiers.
</div>
</div>

View file

@ -0,0 +1,9 @@
# The taClient.addServer() method
This documents the `taClient.addServer()` method.
<div class="warning-box">
<span class="material-icons">warning</span>
<div>
<strong>NOT TO BE USED</strong> This is not a method that should be used. There is only a single CoreServer so don't try adding another one for now.
</div>
</div>

View file

@ -0,0 +1,72 @@
# The taClient.addTournamentPool() method
This documents the `taClient.addTournamentPool()` method.
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Async:</strong> This is a method you would want to use await with
</div>
</div>
This method has input parameters. The function could easily be defined as:
```ts
async function addTournamentPool(tournamentId: string, name: string, image: Uint8Array, maps: Map[]): Promise<Response> {
// backend logic
}
```
`tournamentId` refers to the guid of the tournament.
## General usage:
```ts
const response: Response = taClient.addTournamentPool(tournamentGuid, "Testing Map Pool", convertUrlToUnit8Array('https://png.com/pngPlaceholder'), maps: [map1, map2]);
```
- For the `Map` modal please find documentation at [Modals -> Response](/documentation#Modals/4-Map)
- For `Response` please find documentation at [Modals -> Response](/documentation#Modals/4-Response)
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Note:</strong> Some parameters do not actually have to be provided, but for a complete object to exist you must give it some placeholder value.
</div>
</div>
A the following properties for the maps may be left empty or as a placeholder value. Do note that these are only from the `maps` array, since not all properties must be defined for the `maps`:
- `map.guid`: may be left as `""`
- `map.gameplayParameters.playerSettings`: may be left as an empty [PlayerSpecificSettings](/documentation#Modals/4-PlayerSpecificSettings) object
- `map.attempts` and `map.showScoreboard` will not have any effect on gameplay, hence they can be left as a placeholder value such as `0` and `false`
If you have not yet, please read [Client -> Introduction to the Client](/documentation#Client/3-client-intro)
```js
{
details: {
addTournamentPool: Response_UpdateQualifierEvent,
oneofKind: 'addQualifierMaps'
},
respondingToPacketId: 'packet-guid-uuidv4',
type: Response_ResponseType
}
```
- For `Response_UpdateQualifierEvent` please find documentation at [Modals -> Request_AddQualifierMaps](/documentation#Modals/4-Request_AddQualifierMaps).
```ts
// this method is called when the user submits the AddOrEditMapModal.svelte form
async function handleMapAdded(event: CustomEvent) {
// add the single map that the user configured. This includes all settings and data for the map.
await client.addQualifierMaps(tournamentGuid, qualifierGuid, [event.detail.map]);
// a local method to just "refresh" the data on the page for reactivity
fetchQualifierData();
// a horrible example of how to use confirmations and modals
// show the popup for "Successfully added the map!"
modalMessage = `Successfully added the map!`;
modalIcon = 'check';
modalButtons = [];
modalAutoClose = 1;
showGenericModal = true;
}
```
<div class="info-box">
<span class="material-icons">info</span>
<div>
<strong>Example:</strong> This is a direct example from ShyyTAUI. It comes from the page where users edit qualifiers.
</div>
</div>

View file

@ -71,7 +71,7 @@ The table below shows all of the functions of the taClient. From this point onwa
|setTournamentTeamName()|Set the name of an already existing team in a tournament.|True| |setTournamentTeamName()|Set the name of an already existing team in a tournament.|True|
|showLoadedImage()|**STREAMSYNC MORE DOCS REQUIRED** Show the loaded image that is currently used for streamsync.|True| |showLoadedImage()|**STREAMSYNC MORE DOCS REQUIRED** Show the loaded image that is currently used for streamsync.|True|
|showPrompt()|Show a custom prompt to the users.|True| |showPrompt()|Show a custom prompt to the users.|True|
|stateManager|This is the state manager. Find further documentation, as it is a vital component.|True| |stateManager|This is the state manager. Find further documentation, as it is a vital component.|False|
|updateQualifierMap()|Update the settings of an already existing qualifier map. |True| |updateQualifierMap()|Update the settings of an already existing qualifier map. |True|
|updateTournamentPoolMap()|Update the settings of a map already in a map pool.|True| |updateTournamentPoolMap()|Update the settings of a map already in a map pool.|True|
|updateUser()|**what does this do??? Maybe update the discord Id or what?**Update a user????|True| |updateUser()|**what does this do??? Maybe update the discord Id or what?**Update a user????|True|

View file

@ -15,8 +15,15 @@ There are a couple of important notes for client responses. Since most client re
type: Response_ResponseType type: Response_ResponseType
} }
``` ```
For the definition of the `Response_ResponseType` look at the [Modals -> Response_ResponseType](/documentation#Modals/4-Response_ResponseType) For the definition of the `Response_ResponseType` look at the [Modals -> Response_ResponseType](/documentation#Modals/4-Response_ResponseType).
Generally for responses `details.packetType` will contain the actual data of the response. In order to retreive data from the response in TypeScript, we have to use the `as any` syntax.
```ts
const response = await client.doAction();
let data = (response as any).details.doAction;
```
Where `doAction` is the same as the `response.details.oneofKind`.
<div class="warning-box"> <div class="warning-box">
<span class="material-icons">question_mark</span> <span class="material-icons">question_mark</span>

View file

@ -6,7 +6,7 @@ const docs = import.meta.glob('$lib/taDocs/*.md', {
eager: true eager: true
}); });
export async function GET({ params }) { export async function GET({ params }: { params: { slug: string } }) {
const { slug } = params; const { slug } = params;
// Validate filename to prevent directory traversal attacks // Validate filename to prevent directory traversal attacks

View file

@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { page } from '$app/stores';
import { fly, fade, slide } from 'svelte/transition'; import { fly, fade, slide } from 'svelte/transition';
import { marked } from 'marked'; import { marked } from 'marked';
import 'prismjs'; import 'prismjs';

View file

@ -0,0 +1,42 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { discordDataStore, discordTokenStore, authTokenStore, TAServerPort, TAServerUrl, client, TAServerPlayerPort, TAServerAPIPort } from '$lib/stores';
import { TAClient, Response_ResponseType, Tournament } from 'moons-ta-client';
// Remove 'Bearer ' from the token
if($authTokenStore) {
const cleanToken = $authTokenStore.replace('Bearer ', '');
client.setAuthToken(cleanToken);
}
onMount(async () => {
try {
if(!client.isConnected) {
const connectResult = await client.connect($TAServerUrl, $TAServerPort);
if (connectResult.details.oneofKind === "connect" && connectResult.type === Response_ResponseType.Fail) {
console.error("Failed to connect to TA Core Server", connectResult)
return;
} else {
console.log("Found connect result: ", connectResult)
}
}
} catch (e) {
console.error('Failed to fetch tournaments', e);
}
const tournaments = client.stateManager.getTournaments();
console.log("All Tournaments?:", tournaments)
const oneTournament = client.stateManager.getTournament(tournaments[0].guid);
console.log("One Tournament: ", oneTournament);
// const addqual = await client.addQualifierMaps(tournaments[0].guid, "0f7b58c9-6506-4b3e-9c91-864df109d766", []);
// console.log("addqual ", addqual)
// const addAttempts = client.refundAttempts('fdf9ccd2-74d7-4e12-b890-e7b30d285a66', 'b715a4bf-9461-4613-9086-9de55baf40c3', 'a2e7d397-8839-48dd-bd9a-3d6fa96bc22f', '76561198329760372', 1);
// console.log('refund', addAttempts)
// await client.addTournamentPool()
});
</script>

View file

@ -705,6 +705,8 @@
]; ];
} }
playerModificationStates = [];
showingResultsData = previousMatchResults[0]; showingResultsData = previousMatchResults[0];
showResultsPopup = true; showResultsPopup = true;
} }
@ -823,7 +825,7 @@
} }
} }
async function handleSetGameplayModifiersForUsersVerbose(userIds: string[], modifiers: number) { async function handleSetGameplayModifiersForUsersVerbose(userId: string, modifiers: number) {
try { try {
const results: any[] = []; const results: any[] = [];
@ -836,50 +838,71 @@
let flipBlueUserIds: string[] = []; let flipBlueUserIds: string[] = [];
let flipRedUserIds: string[] = []; let flipRedUserIds: string[] = [];
await Promise.all(userIds.map(userId => { // Determine the desired state from modifiers
const desiredColorSwitched = isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors);
const desiredHandSwitched = isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness);
const desiredBlueDisabled = isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes);
const desiredRedDisabled = isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes);
const userObject = playerModificationStates.find(x => x.platformId == userId); const userObject = playerModificationStates.find(x => x.platformId == userId);
if(!userObject) { if(!userObject) {
if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors)) flipColorUserIds = [...flipColorUserIds, userId]; // User doesn't exist in state, so current state is all false
if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness)) flipHandUserIds = [...flipHandUserIds, userId]; // Send toggle packets for any modifiers that should be enabled
if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes)) flipBlueUserIds = [...flipBlueUserIds, userId]; if(desiredColorSwitched) flipColorUserIds = [...flipColorUserIds, userId];
if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes)) flipRedUserIds = [...flipRedUserIds, userId]; if(desiredHandSwitched) flipHandUserIds = [...flipHandUserIds, userId];
if(desiredBlueDisabled) flipBlueUserIds = [...flipBlueUserIds, userId];
if(desiredRedDisabled) flipRedUserIds = [...flipRedUserIds, userId];
// Add new user with desired state
playerModificationStates = [...playerModificationStates, { playerModificationStates = [...playerModificationStates, {
platformId: userId, platformId: userId,
isColorSwitched: isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors), isColorSwitched: desiredColorSwitched,
isHandSwitched: isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness), isHandSwitched: desiredHandSwitched,
isBlueDisabled: isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes), isBlueDisabled: desiredBlueDisabled,
isRedDisabled: isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes) isRedDisabled: desiredRedDisabled
}]; }];
} else { } else {
if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors) !== userObject.isColorSwitched) flipColorUserIds = [...flipColorUserIds, userId]; // User exists, check which states need to change
if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness) !== userObject.isHandSwitched) flipHandUserIds = [...flipHandUserIds, userId]; if(desiredColorSwitched !== userObject.isColorSwitched) flipColorUserIds = [...flipColorUserIds, userId];
if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes) !== userObject.isBlueDisabled) flipBlueUserIds = [...flipBlueUserIds, userId]; if(desiredHandSwitched !== userObject.isHandSwitched) flipHandUserIds = [...flipHandUserIds, userId];
if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes) !== userObject.isRedDisabled) flipRedUserIds = [...flipRedUserIds, userId]; if(desiredBlueDisabled !== userObject.isBlueDisabled) flipBlueUserIds = [...flipBlueUserIds, userId];
if(desiredRedDisabled !== userObject.isRedDisabled) flipRedUserIds = [...flipRedUserIds, userId];
// Update user state to desired state
playerModificationStates = [...playerModificationStates.filter(x => x.platformId != userId), { playerModificationStates = [...playerModificationStates.filter(x => x.platformId != userId), {
platformId: userId, platformId: userId,
isColorSwitched: !userObject.isColorSwitched, isColorSwitched: desiredColorSwitched,
isHandSwitched: !userObject.isHandSwitched, isHandSwitched: desiredHandSwitched,
isBlueDisabled: !userObject.isBlueDisabled, isBlueDisabled: desiredBlueDisabled,
isRedDisabled: !userObject.isRedDisabled isRedDisabled: desiredRedDisabled
}]; }];
} }
}));
// Only send packets if there are users to modify
if(flipColorUserIds.length > 0) {
console.log('Inverting colors for users:', flipColorUserIds); console.log('Inverting colors for users:', flipColorUserIds);
const response1 = await client.flipColors(tournamentGuid, flipColorUserIds); const response1 = await client.flipColors(tournamentGuid, flipColorUserIds);
results.push({ type: 'InvertColors', response1 }); results.push({ type: 'InvertColors', response: response1 });
}
if(flipHandUserIds.length > 0) {
console.log('Inverting handedness for users:', flipHandUserIds); console.log('Inverting handedness for users:', flipHandUserIds);
const response2 = await client.flipHands(tournamentGuid, flipHandUserIds); const response2 = await client.flipHands(tournamentGuid, flipHandUserIds);
results.push({ type: 'InvertHandedness', response2 }); results.push({ type: 'InvertHandedness', response: response2 });
}
if(flipBlueUserIds.length > 0) {
console.log('Disabling blue notes for users:', flipBlueUserIds); console.log('Disabling blue notes for users:', flipBlueUserIds);
const response3 = await client.disableBlueNotes(tournamentGuid, flipBlueUserIds); const response3 = await client.disableBlueNotes(tournamentGuid, flipBlueUserIds);
results.push({ type: 'DisableBlueNotes', response3 }); results.push({ type: 'DisableBlueNotes', response: response3 });
}
if(flipRedUserIds.length > 0) {
console.log('Disabling red notes for users:', flipRedUserIds); console.log('Disabling red notes for users:', flipRedUserIds);
const response4 = await client.disableRedNotes(tournamentGuid, flipRedUserIds); const response4 = await client.disableRedNotes(tournamentGuid, flipRedUserIds);
results.push({ type: 'DisableRedNotes', response4 }); results.push({ type: 'DisableRedNotes', response: response4 });
}
console.log(`Applied ${results.length} modifiers successfully`); console.log(`Applied ${results.length} modifiers successfully`);
console.log("Modifier apply res", results); console.log("Modifier apply res", results);
@ -901,9 +924,7 @@
async function handleSendModifyGameplay(event: CustomEvent) { async function handleSendModifyGameplay(event: CustomEvent) {
const { platformId, modifiers } = event.detail; const { platformId, modifiers } = event.detail;
const userIds = [platformId]; await handleSetGameplayModifiersForUsersVerbose(platformId, modifiers);
await handleSetGameplayModifiersForUsersVerbose(userIds, modifiers);
} }
const beforeUnloadHandler = (event: BeforeUnloadEvent) => { const beforeUnloadHandler = (event: BeforeUnloadEvent) => {