make the image a length 1 unit 8 array when the tourney image is removed
This commit is contained in:
parent
f220d135ff
commit
1b14a45826
2 changed files with 55 additions and 115 deletions
|
|
@ -113,29 +113,18 @@
|
||||||
{ id: GameplayModifiers_GameOptions.StrictAngles, name: "Strict Angles", description: "Stricter angle enforcement for cuts", enabled: false, group: "Environment" }
|
{ id: GameplayModifiers_GameOptions.StrictAngles, name: "Strict Angles", description: "Stricter angle enforcement for cuts", enabled: false, group: "Environment" }
|
||||||
];
|
];
|
||||||
|
|
||||||
// Group modifiers that can't be active at the same time
|
|
||||||
const incompatibleModifiers = [
|
|
||||||
[GameplayModifiers_GameOptions.SlowSong, GameplayModifiers_GameOptions.FastSong, GameplayModifiers_GameOptions.SuperFastSong],
|
|
||||||
[GameplayModifiers_GameOptions.InstaFail, GameplayModifiers_GameOptions.BatteryEnergy],
|
|
||||||
[GameplayModifiers_GameOptions.BatteryEnergy, GameplayModifiers_GameOptions.ZenMode],
|
|
||||||
[GameplayModifiers_GameOptions.SmallCubes, GameplayModifiers_GameOptions.ProMode],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Custom tournament assistant features
|
// Custom tournament assistant features
|
||||||
let limitAttemptsEnabled = false;
|
let limitAttemptsEnabled = false;
|
||||||
if(map?.taData.gameplayParameters?.attempts !== 0) {
|
if (map?.taData.gameplayParameters?.attempts !== 0) {
|
||||||
limitAttemptsEnabled = true;
|
limitAttemptsEnabled = true;
|
||||||
}
|
}
|
||||||
let numberOfAttempts = map?.taData.gameplayParameters?.attempts; // Default value
|
let numberOfAttempts = map?.taData.gameplayParameters?.attempts || 1;
|
||||||
|
|
||||||
// Initialise modifiers from map data
|
// Initialize modifiers from map data
|
||||||
// map.gameplayParameters?.gameplayModifiers?.options is a decimal number generated by protobuf
|
if (map?.taData.gameplayParameters?.gameplayModifiers?.options) {
|
||||||
if (map && map.taData.gameplayParameters?.gameplayModifiers?.options) {
|
|
||||||
const modifierValue = map.taData.gameplayParameters.gameplayModifiers.options;
|
const modifierValue = map.taData.gameplayParameters.gameplayModifiers.options;
|
||||||
|
|
||||||
// Check each modifier to see if its bit is set in the options value
|
|
||||||
for (const modifier of gameModifiers) {
|
for (const modifier of gameModifiers) {
|
||||||
// Bitwise AND to check if this modifier is enabled
|
|
||||||
modifier.enabled = (modifierValue & modifier.id) === modifier.id;
|
modifier.enabled = (modifierValue & modifier.id) === modifier.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -154,48 +143,43 @@
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleModifierChange(modifier: Modifier) {
|
function updateIncompatibilityStates() {
|
||||||
// Create a new copy of modifiers to work with
|
// Reset all disabled states first
|
||||||
const updatedModifiers = [...gameModifiers];
|
gameModifiers.forEach(modifier => {
|
||||||
|
|
||||||
// Find the modifier in the array and toggle its enabled state
|
|
||||||
const modifierIndex = updatedModifiers.findIndex(m => m.id === modifier.id);
|
|
||||||
if (modifierIndex >= 0) {
|
|
||||||
updatedModifiers[modifierIndex] = {
|
|
||||||
...updatedModifiers[modifierIndex],
|
|
||||||
enabled: modifier.enabled
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the modifier was just turned on
|
|
||||||
if(modifier.enabled) {
|
|
||||||
// check if incompatibilities exist
|
|
||||||
if(modifier.incompatibilites) {
|
|
||||||
// fetch all of the incompatible modifiers
|
|
||||||
let allIncompatableModifiers: Modifier[] = updatedModifiers.filter(x => modifier.incompatibilites?.includes(x.id));
|
|
||||||
// loop through all of the incompatable modifiers and set their enabled and disabled states
|
|
||||||
allIncompatableModifiers.map(async(modifier) => {
|
|
||||||
modifier.enabled = false;
|
|
||||||
modifier.disabled = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if the modifier was just turned off
|
|
||||||
else {
|
|
||||||
if(modifier.incompatibilites) {
|
|
||||||
let allIncompatableModifiers: Modifier[] = updatedModifiers.filter(x => modifier.incompatibilites?.includes(x.id));
|
|
||||||
allIncompatableModifiers.map(async(modifier) => {
|
|
||||||
modifier.disabled = false;
|
modifier.disabled = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check each enabled modifier for incompatibilities
|
||||||
|
gameModifiers
|
||||||
|
.filter(modifier => modifier.enabled && modifier.incompatibilites)
|
||||||
|
.forEach(enabledModifier => {
|
||||||
|
enabledModifier.incompatibilites!.forEach(incompatibleId => {
|
||||||
|
const incompatibleModifier = gameModifiers.find(m => m.id === incompatibleId);
|
||||||
|
if (incompatibleModifier) {
|
||||||
|
// Forcefully disable incompatible modifier
|
||||||
|
incompatibleModifier.enabled = false;
|
||||||
|
// Lock it so it can't be enabled
|
||||||
|
incompatibleModifier.disabled = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the state with the new array
|
function handleModifierChange(changedModifier: Modifier) {
|
||||||
gameModifiers = updatedModifiers;
|
// Find and update the specific modifier
|
||||||
|
const modifierIndex = gameModifiers.findIndex(m => m.id === changedModifier.id);
|
||||||
|
if (modifierIndex >= 0) {
|
||||||
|
gameModifiers[modifierIndex] = { ...changedModifier };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update incompatibility states for all modifiers
|
||||||
|
updateIncompatibilityStates();
|
||||||
|
|
||||||
|
// Trigger reactivity
|
||||||
|
gameModifiers = [...gameModifiers];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveModifiersAsBitmap(): number {
|
function getActiveModifiersAsBitmap(): number {
|
||||||
// Combine all enabled modifiers using bitwise OR
|
|
||||||
return gameModifiers
|
return gameModifiers
|
||||||
.filter(modifier => modifier.enabled)
|
.filter(modifier => modifier.enabled)
|
||||||
.reduce((bitmap, modifier) => bitmap | modifier.id, 0);
|
.reduce((bitmap, modifier) => bitmap | modifier.id, 0);
|
||||||
|
|
@ -208,9 +192,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle characteristic selection change
|
|
||||||
function handleCharacteristicChange() {
|
function handleCharacteristicChange() {
|
||||||
// Reset difficulty when characteristic changes
|
|
||||||
selectedDifficulty = availableDifficulties[selectedCharacteristic]?.[0] || "";
|
selectedDifficulty = availableDifficulties[selectedCharacteristic]?.[0] || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -219,10 +201,7 @@
|
||||||
mapLoadError = null;
|
mapLoadError = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to determine if the input is a hash or a key
|
|
||||||
const isHash = /^[0-9a-fA-F]{40}$/.test(key);
|
const isHash = /^[0-9a-fA-F]{40}$/.test(key);
|
||||||
|
|
||||||
// Construct the appropriate API endpoint
|
|
||||||
const endpoint = isHash
|
const endpoint = isHash
|
||||||
? `https://api.beatsaver.com/maps/hash/${key}`
|
? `https://api.beatsaver.com/maps/hash/${key}`
|
||||||
: `https://api.beatsaver.com/maps/id/${key}`;
|
: `https://api.beatsaver.com/maps/id/${key}`;
|
||||||
|
|
@ -234,8 +213,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: BeatSaverMap = await response.json();
|
const data: BeatSaverMap = await response.json();
|
||||||
|
|
||||||
// Use the latest version
|
|
||||||
const latestVersion = data.versions[0];
|
const latestVersion = data.versions[0];
|
||||||
|
|
||||||
// Map basic details
|
// Map basic details
|
||||||
|
|
@ -250,7 +227,6 @@
|
||||||
new Set(latestVersion.diffs.map(diff => diff.characteristic))
|
new Set(latestVersion.diffs.map(diff => diff.characteristic))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Group difficulties by characteristic
|
|
||||||
availableDifficulties = {};
|
availableDifficulties = {};
|
||||||
for (const diff of latestVersion.diffs) {
|
for (const diff of latestVersion.diffs) {
|
||||||
if (!availableDifficulties[diff.characteristic]) {
|
if (!availableDifficulties[diff.characteristic]) {
|
||||||
|
|
@ -259,11 +235,9 @@
|
||||||
availableDifficulties[diff.characteristic].push(diff.difficulty);
|
availableDifficulties[diff.characteristic].push(diff.difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set initial selections
|
|
||||||
selectedCharacteristic = availableCharacteristics[0] || "";
|
selectedCharacteristic = availableCharacteristics[0] || "";
|
||||||
selectedDifficulty = availableDifficulties[selectedCharacteristic]?.[0] || "";
|
selectedDifficulty = availableDifficulties[selectedCharacteristic]?.[0] || "";
|
||||||
|
|
||||||
// Set Beat Saver ID for the map
|
|
||||||
mapBeatmapId = `custom_level_${latestVersion.hash.toUpperCase()}`;
|
mapBeatmapId = `custom_level_${latestVersion.hash.toUpperCase()}`;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
@ -276,6 +250,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDifficultyNumber(difficulty: string): number {
|
||||||
|
switch (difficulty) {
|
||||||
|
case "Easy": return 0;
|
||||||
|
case "Normal": return 1;
|
||||||
|
case "Hard": return 2;
|
||||||
|
case "Expert": return 3;
|
||||||
|
case "Expert+":
|
||||||
|
case "ExpertPlus": return 4;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
if (!mapName || !mapBeatmapId) {
|
if (!mapName || !mapBeatmapId) {
|
||||||
error = "Map name and beatmap ID are required";
|
error = "Map name and beatmap ID are required";
|
||||||
|
|
@ -291,54 +277,26 @@
|
||||||
error = null;
|
error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Connect to the TA server
|
|
||||||
const connectResult = await client.connect($TAServerUrl, $TAServerPort);
|
const connectResult = await client.connect($TAServerUrl, $TAServerPort);
|
||||||
|
|
||||||
if (connectResult.details.oneofKind === "connect" && connectResult.type === Response_ResponseType.Fail) {
|
if (connectResult.details.oneofKind === "connect" && connectResult.type === Response_ResponseType.Fail) {
|
||||||
throw new Error(connectResult.details.connect.message);
|
throw new Error(connectResult.details.connect.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join the tournament
|
|
||||||
const joinResult = await client.joinTournament(tournamentGuid);
|
const joinResult = await client.joinTournament(tournamentGuid);
|
||||||
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');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get modifiers as a bitmap
|
|
||||||
const modifiersBitmap = getActiveModifiersAsBitmap();
|
const modifiersBitmap = getActiveModifiersAsBitmap();
|
||||||
|
|
||||||
// Add custom data for "Limit Attempts" if enabled
|
|
||||||
const customData: any = {};
|
|
||||||
if (limitAttemptsEnabled) {
|
|
||||||
customData.limitAttempts = {
|
|
||||||
enabled: true,
|
|
||||||
count: numberOfAttempts
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mapDifficulty: number = 0;
|
|
||||||
if(selectedDifficulty == "Easy") {
|
|
||||||
mapDifficulty = 0;
|
|
||||||
} else if(selectedDifficulty == "Normal") {
|
|
||||||
mapDifficulty = 1;
|
|
||||||
} else if(selectedDifficulty == "Hard") {
|
|
||||||
mapDifficulty = 2;
|
|
||||||
} else if(selectedDifficulty == "Expert") {
|
|
||||||
mapDifficulty = 3;
|
|
||||||
} else if(selectedDifficulty == "Expert+") {
|
|
||||||
mapDifficulty = 4;
|
|
||||||
} else if(selectedDifficulty == "ExpertPlus") {
|
|
||||||
mapDifficulty = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new map object or update existing one
|
|
||||||
const mapData: Map = {
|
const mapData: Map = {
|
||||||
guid: map?.taData.guid || uuidv4(),
|
guid: map?.taData.guid || uuidv4(),
|
||||||
gameplayParameters: {
|
gameplayParameters: {
|
||||||
beatmap: {
|
beatmap: {
|
||||||
name: mapName,
|
name: mapName,
|
||||||
levelId: mapBeatmapId,
|
levelId: mapBeatmapId,
|
||||||
difficulty: mapDifficulty,
|
difficulty: getDifficultyNumber(selectedDifficulty),
|
||||||
characteristic: {
|
characteristic: {
|
||||||
serializedName: selectedCharacteristic,
|
serializedName: selectedCharacteristic,
|
||||||
difficulties: []
|
difficulties: []
|
||||||
|
|
@ -347,7 +305,7 @@
|
||||||
gameplayModifiers: {
|
gameplayModifiers: {
|
||||||
options: modifiersBitmap
|
options: modifiersBitmap
|
||||||
},
|
},
|
||||||
attempts: numberOfAttempts || 0,
|
attempts: limitAttemptsEnabled ? numberOfAttempts : 0,
|
||||||
disableCustomNotesOnStream: false,
|
disableCustomNotesOnStream: false,
|
||||||
disableFail: false,
|
disableFail: false,
|
||||||
disablePause: false,
|
disablePause: false,
|
||||||
|
|
@ -360,13 +318,11 @@
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
if (map) {
|
if (map) {
|
||||||
// Update existing map
|
|
||||||
response = await client.updateTournamentPoolMap(tournamentGuid, poolGuid, mapData);
|
response = await client.updateTournamentPoolMap(tournamentGuid, poolGuid, mapData);
|
||||||
if (response.type === Response_ResponseType.Success) {
|
if (response.type === Response_ResponseType.Success) {
|
||||||
dispatch('mapUpdated');
|
dispatch('mapUpdated');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add new map
|
|
||||||
response = await client.addTournamentPoolMaps(tournamentGuid, poolGuid, [mapData]);
|
response = await client.addTournamentPoolMaps(tournamentGuid, poolGuid, [mapData]);
|
||||||
if (response.type === Response_ResponseType.Success) {
|
if (response.type === Response_ResponseType.Success) {
|
||||||
dispatch('mapAdded');
|
dispatch('mapAdded');
|
||||||
|
|
@ -391,39 +347,23 @@
|
||||||
dispatch('close');
|
dispatch('close');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise from existing map data if available
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// Initialise disabled states based on incompatible groups
|
// Initialize incompatibility states based on existing enabled modifiers
|
||||||
for (const incompatibleGroup of incompatibleModifiers) {
|
updateIncompatibilityStates();
|
||||||
// Find any enabled modifier in this group
|
|
||||||
const enabledModifier = gameModifiers.find(m =>
|
|
||||||
incompatibleGroup.includes(m.id) && m.enabled
|
|
||||||
);
|
|
||||||
|
|
||||||
// If there's an enabled modifier, disable others in the same group
|
if (map?.taData.gameplayParameters?.beatmap?.levelId) {
|
||||||
if (enabledModifier) {
|
|
||||||
for (const modifierToUpdate of gameModifiers) {
|
|
||||||
if (incompatibleGroup.includes(modifierToUpdate.id) &&
|
|
||||||
modifierToUpdate.id !== enabledModifier.id) {
|
|
||||||
modifierToUpdate.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (map && map.taData.gameplayParameters?.beatmap?.levelId) {
|
|
||||||
// Extract hash from levelId (format: custom_level_HASH)
|
|
||||||
const levelIdParts = map.taData.gameplayParameters.beatmap.levelId.split('_');
|
const levelIdParts = map.taData.gameplayParameters.beatmap.levelId.split('_');
|
||||||
if (levelIdParts.length === 3) {
|
if (levelIdParts.length === 3) {
|
||||||
beatSaverKey = levelIdParts[2];
|
beatSaverKey = levelIdParts[2];
|
||||||
fetchMapFromBeatSaver(beatSaverKey);
|
fetchMapFromBeatSaver(beatSaverKey);
|
||||||
|
|
||||||
// For existing maps, try to set the characteristic and difficulty
|
|
||||||
if (map.taData.gameplayParameters?.beatmap?.characteristic) {
|
if (map.taData.gameplayParameters?.beatmap?.characteristic) {
|
||||||
selectedCharacteristic = map.taData.gameplayParameters.beatmap.characteristic.serializedName;
|
selectedCharacteristic = map.taData.gameplayParameters.beatmap.characteristic.serializedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map.taData.gameplayParameters?.beatmap?.difficulty) {
|
if (map.taData.gameplayParameters?.beatmap?.difficulty !== undefined) {
|
||||||
selectedDifficulty = MapDifficulty[map.taData.gameplayParameters.beatmap.characteristic?.difficulties[0]!];
|
const difficultyNames = ["Easy", "Normal", "Hard", "Expert", "Expert+"];
|
||||||
|
selectedDifficulty = difficultyNames[map.taData.gameplayParameters.beatmap.difficulty] || "Easy";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,6 @@ export async function linkToUint8Array(link: string): Promise<Uint8Array> {
|
||||||
throw new Error(`Failed to fetch image: ${error instanceof Error ? error.message : String(error)}`);
|
throw new Error(`Failed to fetch image: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported link format. Must be a data URL or HTTP/HTTPS URL');
|
return new Uint8Array(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue