Skip to content

Commit

Permalink
feat: map selector refresh button
Browse files Browse the repository at this point in the history
  • Loading branch information
tsa96 committed Nov 23, 2024
1 parent fdb073b commit a528639
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 6 deletions.
12 changes: 7 additions & 5 deletions layout/pages/map-selector/map-selector.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@
<Image class="search__clearicon" src="file://{images}/close.svg" textureheight="32" />
</Button>
</Panel>
<Panel class="mapselector-header__filters">
<Button class="button button--green ml-2" onactivate="MapSelectorHandler.requestMapUpdate()">
<Label class="button__text" text="#Common_Update" />
<TooltipPanel class="mr-2" tooltip="#MapSelector_Updates_Check">
<Button class="button" onactivate="MapSelectorHandler.checkForUpdates()">
<Image id="RefreshIcon" class="button__icon" src="file://{images}/refresh.svg" textureheight="32" />
</Button>
<Button id="FilterErase" class="ml-2 button button--red" onactivate="MapSelectorHandler.clearFilters()">
</TooltipPanel>
<TooltipPanel tooltip="#MapSelector_Filters_Reset">
<Button class="button button--red" onactivate="MapSelectorHandler.clearFilters()">
<Image class="button__icon" src="file://{images}/filter-remove.svg" textureheight="32" />
</Button>
</Panel>
</TooltipPanel>
</Panel>
<Panel id="MapFilters" class="mapselector-filters">
<Panel class="mapselector-filters__row mapselector-filters__gamemodes">
Expand Down
99 changes: 98 additions & 1 deletion scripts/pages/map-selector/map-selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class MapSelectorHandler implements OnPanelLoad {
unranked: $<Button>('#MapListUnranked'),
beta: $<Button>('#MapListBeta')
},
refreshIcon: $<Image>('#RefreshIcon')
};

// Describing which data on which type of panel we want to store out to PS.
Expand Down Expand Up @@ -345,7 +346,7 @@ class MapSelectorHandler implements OnPanelLoad {

info.SetDialogVariableInt('tier', Maps.getTier(staticData, gamemode) ?? 0);
info.SetDialogVariableInt('numZones', Leaderboards.getNumZones(staticData));
info.SetDialogVariable('type', mainTrack.linear ? this.strings.staged : this.strings.linear);
info.SetDialogVariable('layout', mainTrack.linear ? this.strings.staged : this.strings.linear);

info.SetDialogVariable('description', staticData.info?.description);
this.panels.descriptionContainer.SetHasClass('hide', !staticData.info?.description);
Expand Down Expand Up @@ -504,4 +505,100 @@ class MapSelectorHandler implements OnPanelLoad {
this.panels.leaderboardContainer.SetHasClass('mapselector-leaderboards--open', open);
$.persistentStorage.setItem('mapSelector.leaderboardsOpen', open);
}

checkingUpdates = false;
lastUpdateCheck = 0;

checkForUpdates() {
if (this.checkingUpdates || this.lastUpdateCheck + REFRESH_COOLDOWN > Date.now()) {
return;
}

this.lastUpdateCheck = Date.now();

this.panels.refreshIcon.AddClass('spin-clockwise');

// Has to handle both private and static map updates, where we only need private if we're in the beta, and we
// could need 0, 1 or 2 static updates, depending on the response from the version check. So logic gets quite
// complicated, all for one loading spinner. I want RxJS!
let updatesNeeded = 0;
let fetchedStaticVersions = false;
let errored = false;
if (this.panels.listTypes.beta.IsSelected()) {
updatesNeeded++;

const privHandle = $.RegisterForUnhandledEvent('MapCache_PrivateMapsUpdate', (success: boolean) => {
$.UnregisterForUnhandledEvent('MapCache_PrivateMapsUpdate', privHandle);

if (!success) {
errored = true;
}

updatesNeeded--;

if (updatesNeeded === 0 && fetchedStaticVersions) {
this.onFinishUpdate(errored, {
message: '#MapSelector_Updates_Updated',
style: ToastStyle.SUCCESS
});
}
});

MapCacheAPI.FetchPrivateMaps();
}

const versionsHandle = $.RegisterForUnhandledEvent(
'MapCache_StaticCacheVersionChecked',
(staticUpdatesNeeded) => {
$.UnregisterForUnhandledEvent('MapCache_StaticCacheVersionChecked', versionsHandle);

fetchedStaticVersions = true;

if (staticUpdatesNeeded === 0) {
if (updatesNeeded === 0) {
this.onFinishUpdate(errored, {
message: '#MapSelector_Updates_UpToDate',
style: ToastStyle.INFO
});
}
return;
}

updatesNeeded += staticUpdatesNeeded;
let staticUpdates = 0;
const staticHandle = $.RegisterForUnhandledEvent('MapCache_StaticCacheUpdate', (_type, success) => {
if (!success) {
errored = true;
}

staticUpdates++;
if (staticUpdates === staticUpdatesNeeded) {
$.UnregisterForUnhandledEvent('MapCache_StaticCacheUpdate', staticHandle);
}

--updatesNeeded;
if (updatesNeeded === 0) {
this.onFinishUpdate(errored, {
message: '#MapSelector_Updates_Updated',
style: ToastStyle.SUCCESS
});
}
});
}
);

this.checkingUpdates = true;
MapCacheAPI.CheckForUpdates();
}

onFinishUpdate(errored: boolean, toast: ToastCreateArgs) {
// If we errored at any point, C++ will show a toast. Even if some requests were successful, don't show
// both success and error toasts, would be confusing.
if (!errored) {
ToastManager.createToast(toast);
}

this.panels.refreshIcon.RemoveClass('spin-clockwise');
this.checkingUpdates = false;
}
}
6 changes: 6 additions & 0 deletions scripts/types-mom/apis.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ declare namespace MapCacheAPI {

/** Returns true if the given mapID is queued from download */
function MapQueuedForDownload(mapID: int32): boolean;

/** Checks backend for latest static cache versions, download if out-of-date */
function CheckForUpdates(): void;

/** Fetches private maps visible to the user */
function FetchPrivateMaps(): void;
}

declare namespace SpectatorAPI {
Expand Down
17 changes: 17 additions & 0 deletions scripts/types-mom/events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ interface GlobalEventNameMap {
/** Fired when the selected map has its data update */
MapSelector_SelectedDataUpdate: (mapData: MapCacheAPI.MapData) => void;

/**
* Fired when lives stats for the selected map have been updated.
* These are fetched from the backend when a map is selected, with a 60s cooldown. If we're outside the cooldown,
* the event fires once we get a response from backend, otherwise it fires immediately after
* `MapSelector_SelectedDataUpdate`.
*/
MapSelector_SelectedOnlineDataUpdate: (stats: import('common/web').MapStats) => void;

PanoramaComponent_SteamLobby_OnListUpdated: (lobbyList: import('common/online').GroupedLobbyLists) => void;

PanoramaComponent_SteamLobby_OnDataUpdated: (lobbyData: import('common/online').LobbyList) => void;
Expand Down Expand Up @@ -81,6 +89,15 @@ interface GlobalEventNameMap {

MapCache_SearchComplete: (success: boolean) => void;

/** Fired when a static map list is updated from backend */
MapCache_StaticCacheUpdate: (type: import('common/maps').MapListType, success: boolean) => void;

/** Fired when finished checking latest static cache versions */
MapCache_StaticCacheVersionChecked: (updatesNeeded: 0 | 1 | 2) => void;

/** Fired when the private map lists are updated from online */
MapCache_PrivateMapsUpdate: (success: boolean) => void;

MapDownload_Queued: (mapID: uint32, added: boolean) => void;

MapDownload_Start: (mapID: uint32, mapName: string) => void;
Expand Down

0 comments on commit a528639

Please sign in to comment.