diff --git a/package-lock.json b/package-lock.json
index feccdb5..c46238d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -715,6 +715,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -1033,6 +1034,7 @@
"integrity": "sha512-4XyY1SCB/Eyz8E9G7SEBKViysYwVtDftuA7kyQ5bmuFNPWC1KZC4988rMvaJxhH2BbCTsbLPjNOZwiEGXt8/2g==",
"hasInstallScript": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/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",
"integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
"debug": "^4.3.4",
@@ -1598,6 +1601,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz",
"integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==",
"devOptional": true,
+ "peer": true,
"dependencies": {
"undici-types": "~6.19.2"
}
@@ -1812,6 +1816,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001669",
"electron-to-chromium": "^1.5.41",
@@ -2338,6 +2343,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">=12"
}
@@ -6373,6 +6379,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.1.1",
@@ -6433,6 +6440,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "peer": true,
"dependencies": {
"lilconfig": "^3.0.0",
"yaml": "^2.3.4"
@@ -6611,6 +6619,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/estree": "1.0.6"
},
@@ -6997,6 +7006,7 @@
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz",
"integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
@@ -7234,6 +7244,7 @@
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7307,6 +7318,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
diff --git a/src/lib/taDocs/1-installation.md b/src/lib/taDocs/1-installation.md
index 8f69c5f..07ca485 100644
--- a/src/lib/taDocs/1-installation.md
+++ b/src/lib/taDocs/1-installation.md
@@ -38,7 +38,7 @@ The connectResult has the following schema:
respondingToPacketId: 'Packet-Guid',
details: {
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: [],
matches: [],
qualifiers: [],
- settings: [Object],
- server: [Object]
+ settings: Object,
+ server: Object
}
],
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.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.
diff --git a/src/lib/taDocs/1-taInfo.md b/src/lib/taDocs/1-taInfo.md
index 12bcc16..b23be30 100644
--- a/src/lib/taDocs/1-taInfo.md
+++ b/src/lib/taDocs/1-taInfo.md
@@ -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.
-- 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.
diff --git a/src/lib/taDocs/2-stateManager-intro.md b/src/lib/taDocs/2-stateManager-intro.md
index 9b2f510..47d4200 100644
--- a/src/lib/taDocs/2-stateManager-intro.md
+++ b/src/lib/taDocs/2-stateManager-intro.md
@@ -1,5 +1,5 @@
# 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.
diff --git a/src/lib/taDocs/3-client-addAuthorizedUser.md b/src/lib/taDocs/3-client-addAuthorizedUser.md
index a435f57..8142519 100644
--- a/src/lib/taDocs/3-client-addAuthorizedUser.md
+++ b/src/lib/taDocs/3-client-addAuthorizedUser.md
@@ -1,6 +1,13 @@
# The taClient.addAuthorizedUser() method
This documents the `taClient.addAuthorizedUser()` method.
+
+
info
+
+ Async: This is a method you would want to use await with
+
+
+
This method has input parameters. The function could easily be defined as:
```ts
async function addAuthorizedUser(tournamentId: string, discordId: string, roleIds: string[]): Promise {
@@ -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.
-- 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
{
details: {
@@ -27,6 +31,8 @@ The `response` variable from above will actually be a 'mashup' of two types. Fir
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).
info
@@ -36,7 +42,24 @@ The `response` variable from above will actually be a 'mashup' of two types. Fir
```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.";
+}
```
info
diff --git a/src/lib/taDocs/3-client-addQualifierMaps.md b/src/lib/taDocs/3-client-addQualifierMaps.md
new file mode 100644
index 0000000..bb98140
--- /dev/null
+++ b/src/lib/taDocs/3-client-addQualifierMaps.md
@@ -0,0 +1,72 @@
+# The taClient.addQualifierMaps() method
+This documents the `taClient.addQualifierMaps()` method.
+
+
+
info
+
+ Async: This is a method you would want to use await with
+
+
+
+This method has input parameters. The function could easily be defined as:
+```ts
+async function addQualifierMaps(tournamentId: string, qualifierId: string, maps: Map[]): Promise
{
+ // 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)
+
+
+
info
+
+ Note: Some parameters do not actually have to be provided, but for a complete object to exist you must give it some placeholder value.
+
+
+
+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;
+}
+```
+
+
info
+
+ Example: This is a direct example from ShyyTAUI. It comes from the page where users edit qualifiers.
+
+
\ No newline at end of file
diff --git a/src/lib/taDocs/3-client-addServer.md b/src/lib/taDocs/3-client-addServer.md
new file mode 100644
index 0000000..e31d7d2
--- /dev/null
+++ b/src/lib/taDocs/3-client-addServer.md
@@ -0,0 +1,9 @@
+# The taClient.addServer() method
+This documents the `taClient.addServer()` method.
+
+
+
warning
+
+ NOT TO BE USED This is not a method that should be used. There is only a single CoreServer so don't try adding another one for now.
+
+
diff --git a/src/lib/taDocs/3-client-addTournamentPool.md b/src/lib/taDocs/3-client-addTournamentPool.md
new file mode 100644
index 0000000..4a51139
--- /dev/null
+++ b/src/lib/taDocs/3-client-addTournamentPool.md
@@ -0,0 +1,72 @@
+# The taClient.addTournamentPool() method
+This documents the `taClient.addTournamentPool()` method.
+
+
+
info
+
+ Async: This is a method you would want to use await with
+
+
+
+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 {
+ // 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)
+
+
+
info
+
+ Note: Some parameters do not actually have to be provided, but for a complete object to exist you must give it some placeholder value.
+
+
+
+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;
+}
+```
+
+
info
+
+ Example: This is a direct example from ShyyTAUI. It comes from the page where users edit qualifiers.
+
+
\ No newline at end of file
diff --git a/src/lib/taDocs/3-client-allFunctions.md b/src/lib/taDocs/3-client-allFunctions.md
index 70d0f58..d583faa 100644
--- a/src/lib/taDocs/3-client-allFunctions.md
+++ b/src/lib/taDocs/3-client-allFunctions.md
@@ -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|
|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|
-|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|
|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|
diff --git a/src/lib/taDocs/3-client-intro.md b/src/lib/taDocs/3-client-intro.md
index cce6690..b1efc3b 100644
--- a/src/lib/taDocs/3-client-intro.md
+++ b/src/lib/taDocs/3-client-intro.md
@@ -15,8 +15,15 @@ There are a couple of important notes for client responses. Since most client re
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`.
question_mark
diff --git a/src/routes/api/docs/[slug]/+server.ts b/src/routes/api/docs/[slug]/+server.ts
index 18352ed..731f855 100644
--- a/src/routes/api/docs/[slug]/+server.ts
+++ b/src/routes/api/docs/[slug]/+server.ts
@@ -6,7 +6,7 @@ const docs = import.meta.glob('$lib/taDocs/*.md', {
eager: true
});
-export async function GET({ params }) {
+export async function GET({ params }: { params: { slug: string } }) {
const { slug } = params;
// Validate filename to prevent directory traversal attacks
diff --git a/src/routes/documentation/+page.svelte b/src/routes/documentation/+page.svelte
index 1fa5ddd..d3b4acf 100644
--- a/src/routes/documentation/+page.svelte
+++ b/src/routes/documentation/+page.svelte
@@ -1,6 +1,5 @@
\ No newline at end of file
diff --git a/src/routes/tournaments/[tournamentguid]/matches/[matchGuid]/+page.svelte b/src/routes/tournaments/[tournamentguid]/matches/[matchGuid]/+page.svelte
index e9461b1..61d446d 100644
--- a/src/routes/tournaments/[tournamentguid]/matches/[matchGuid]/+page.svelte
+++ b/src/routes/tournaments/[tournamentguid]/matches/[matchGuid]/+page.svelte
@@ -705,6 +705,8 @@
];
}
+ playerModificationStates = [];
+
showingResultsData = previousMatchResults[0];
showResultsPopup = true;
}
@@ -823,73 +825,94 @@
}
}
- async function handleSetGameplayModifiersForUsersVerbose(userIds: string[], modifiers: number) {
- try {
- const results: any[] = [];
+ async function handleSetGameplayModifiersForUsersVerbose(userId: string, modifiers: number) {
+ try {
+ const results: any[] = [];
- const isModifierEnabled = (modifier: Command_ModifyGameplay_Modifier): boolean => {
- return (modifiers & (1 << modifier)) !== 0;
- };
+ const isModifierEnabled = (modifier: Command_ModifyGameplay_Modifier): boolean => {
+ return (modifiers & (1 << modifier)) !== 0;
+ };
- let flipColorUserIds: string[] = [];
- let flipHandUserIds: string[] = [];
- let flipBlueUserIds: string[] = [];
- let flipRedUserIds: string[] = [];
+ let flipColorUserIds: string[] = [];
+ let flipHandUserIds: string[] = [];
+ let flipBlueUserIds: string[] = [];
+ let flipRedUserIds: string[] = [];
- await Promise.all(userIds.map(userId => {
- const userObject = playerModificationStates.find(x => x.platformId == userId);
- if(!userObject) {
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors)) flipColorUserIds = [...flipColorUserIds, userId];
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness)) flipHandUserIds = [...flipHandUserIds, userId];
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes)) flipBlueUserIds = [...flipBlueUserIds, userId];
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes)) flipRedUserIds = [...flipRedUserIds, userId];
- playerModificationStates = [...playerModificationStates, {
- platformId: userId,
- isColorSwitched: isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors),
- isHandSwitched: isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness),
- isBlueDisabled: isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes),
- isRedDisabled: isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes)
- }];
- } else {
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertColors) !== userObject.isColorSwitched) flipColorUserIds = [...flipColorUserIds, userId];
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.InvertHandedness) !== userObject.isHandSwitched) flipHandUserIds = [...flipHandUserIds, userId];
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableBlueNotes) !== userObject.isBlueDisabled) flipBlueUserIds = [...flipBlueUserIds, userId];
- if(isModifierEnabled(Command_ModifyGameplay_Modifier.DisableRedNotes) !== userObject.isRedDisabled) flipRedUserIds = [...flipRedUserIds, userId];
- playerModificationStates = [...playerModificationStates.filter(x => x.platformId != userId), {
- platformId: userId,
- isColorSwitched: !userObject.isColorSwitched,
- isHandSwitched: !userObject.isHandSwitched,
- isBlueDisabled: !userObject.isBlueDisabled,
- isRedDisabled: !userObject.isRedDisabled
- }];
- }
- }));
+ // 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);
+
+ if(!userObject) {
+ // User doesn't exist in state, so current state is all false
+ // Send toggle packets for any modifiers that should be enabled
+ if(desiredColorSwitched) flipColorUserIds = [...flipColorUserIds, userId];
+ if(desiredHandSwitched) flipHandUserIds = [...flipHandUserIds, userId];
+ if(desiredBlueDisabled) flipBlueUserIds = [...flipBlueUserIds, userId];
+ if(desiredRedDisabled) flipRedUserIds = [...flipRedUserIds, userId];
+
+ // Add new user with desired state
+ playerModificationStates = [...playerModificationStates, {
+ platformId: userId,
+ isColorSwitched: desiredColorSwitched,
+ isHandSwitched: desiredHandSwitched,
+ isBlueDisabled: desiredBlueDisabled,
+ isRedDisabled: desiredRedDisabled
+ }];
+ } else {
+ // User exists, check which states need to change
+ if(desiredColorSwitched !== userObject.isColorSwitched) flipColorUserIds = [...flipColorUserIds, userId];
+ if(desiredHandSwitched !== userObject.isHandSwitched) flipHandUserIds = [...flipHandUserIds, 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), {
+ platformId: userId,
+ isColorSwitched: desiredColorSwitched,
+ isHandSwitched: desiredHandSwitched,
+ isBlueDisabled: desiredBlueDisabled,
+ isRedDisabled: desiredRedDisabled
+ }];
+ }
+
+ // Only send packets if there are users to modify
+ if(flipColorUserIds.length > 0) {
console.log('Inverting colors for users:', 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);
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);
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);
const response4 = await client.disableRedNotes(tournamentGuid, flipRedUserIds);
- results.push({ type: 'DisableRedNotes', response4 });
-
- console.log(`Applied ${results.length} modifiers successfully`);
- console.log("Modifier apply res", results);
- return results;
-
- } catch (error) {
- console.error('Error applying gameplay modifiers:', error);
- throw error;
+ results.push({ type: 'DisableRedNotes', response: response4 });
}
+
+ console.log(`Applied ${results.length} modifiers successfully`);
+ console.log("Modifier apply res", results);
+ return results;
+
+ } catch (error) {
+ console.error('Error applying gameplay modifiers:', error);
+ throw error;
}
+}
async function handleModifyGameplayForPlayer(player: User) {
editingPlayerName = player.name;
@@ -900,10 +923,8 @@
async function handleSendModifyGameplay(event: CustomEvent) {
const { platformId, modifiers } = event.detail;
-
- const userIds = [platformId];
-
- await handleSetGameplayModifiersForUsersVerbose(userIds, modifiers);
+
+ await handleSetGameplayModifiersForUsersVerbose(platformId, modifiers);
}
const beforeUnloadHandler = (event: BeforeUnloadEvent) => {