From 5e2dd1003570166145d1188b8bc3a49c2d7b47e0 Mon Sep 17 00:00:00 2001 From: MathieuG-P Date: Sun, 6 Nov 2022 01:38:31 +0100 Subject: [PATCH] fully load local maps, and prepare bsaver map infos --- src/main/ipcs/bs-maps-ipcs.ts | 18 ++++ src/main/ipcs/index.ts | 1 + .../services/installation-location.service.ts | 18 +++- .../maps/local-maps-manager.service.ts | 91 +++++++++++++++++++ src/main/services/utils.service.ts | 4 +- .../available-versions-slide.component.tsx | 4 - .../available-versions-slider.component.tsx | 4 +- .../maps-playlists-panel.component.tsx | 22 +++-- src/renderer/helpers/array-tools.ts | 7 ++ .../available-versions-list.components.tsx | 2 +- src/renderer/pages/maps-page.component.tsx | 4 +- src/renderer/services/beat-saver.service.ts | 18 ++++ src/renderer/services/maps-manager.service.ts | 16 +++- src/shared/models/maps/index.ts | 15 +++ 14 files changed, 200 insertions(+), 24 deletions(-) create mode 100644 src/main/ipcs/bs-maps-ipcs.ts create mode 100644 src/main/services/maps/local-maps-manager.service.ts create mode 100644 src/renderer/helpers/array-tools.ts create mode 100644 src/renderer/services/beat-saver.service.ts create mode 100644 src/shared/models/maps/index.ts diff --git a/src/main/ipcs/bs-maps-ipcs.ts b/src/main/ipcs/bs-maps-ipcs.ts new file mode 100644 index 00000000..d378c643 --- /dev/null +++ b/src/main/ipcs/bs-maps-ipcs.ts @@ -0,0 +1,18 @@ +import { ipcMain } from "electron"; +import { LocalMapsManagerService } from "../services/maps/local-maps-manager.service"; +import { UtilsService } from "../services/utils.service"; +import { BSVersion } from "shared/bs-version.interface"; +import { IpcRequest } from "shared/models/ipc"; +import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"; + +ipcMain.on('get-version-maps', (event, request: IpcRequest) => { + const utilsService = UtilsService.getInstance(); + const localMaps = LocalMapsManagerService.getInstance(); + + localMaps.getMaps(request.args).then(maps => { + utilsService.ipcSend(request.responceChannel, {success: true, data: maps}); + }).catch(() => { + utilsService.ipcSend(request.responceChannel, {success: false}); + }) + + }); \ No newline at end of file diff --git a/src/main/ipcs/index.ts b/src/main/ipcs/index.ts index 397a23be..7712adff 100644 --- a/src/main/ipcs/index.ts +++ b/src/main/ipcs/index.ts @@ -8,3 +8,4 @@ import './supporters-ipcs'; import './launcher-ipcs'; import './window-manager-ipcs'; import './bs-mods-ipcs'; +import './bs-maps-ipcs'; diff --git a/src/main/services/installation-location.service.ts b/src/main/services/installation-location.service.ts index 4503d552..a5cc14ae 100644 --- a/src/main/services/installation-location.service.ts +++ b/src/main/services/installation-location.service.ts @@ -12,6 +12,11 @@ export class InstallationLocationService { private readonly INSTALLATION_FOLDER = "BSManager"; private readonly VERSIONS_FOLDER = "BSInstances"; + + private readonly SHARED_CONTENT_FOLDER = "SharedContent"; + private readonly SHARED_MAPS_FOLDER = "SharedMaps"; + private readonly SHARED_PLAYLISTS_FOLDER = "SharedPlaylists"; + private readonly STORE_INSTALLATION_PATH_KEY = "installation-folder"; @@ -36,9 +41,6 @@ export class InstallationLocationService { this._installationDirectory = this.configService.get(this.STORE_INSTALLATION_PATH_KEY) || app.getPath("documents"); } - public get installationDirectory(): string{ return path.join(this._installationDirectory, this.INSTALLATION_FOLDER); } - public get versionsDirectory(): string { return path.join(this.installationDirectory, this.VERSIONS_FOLDER); } - public setInstallationDirectory(newDir: string): Promise{ const oldDir = this.installationDirectory; const newDest = path.join(newDir, this.INSTALLATION_FOLDER); @@ -53,7 +55,15 @@ export class InstallationLocationService { log.error(err); }) }) - } + public get installationDirectory(): string{ return path.join(this._installationDirectory, this.INSTALLATION_FOLDER); } + + public get versionsDirectory(): string { return path.join(this.installationDirectory, this.VERSIONS_FOLDER); } + + public get sharedContentPath(): string { return path.join(this.installationDirectory, this.SHARED_CONTENT_FOLDER); } + public get sharedMapsPath(): string { return path.join(this.sharedContentPath, this.SHARED_MAPS_FOLDER); } + public get sharedPlaylistsPath(): string { return path.join(this.sharedContentPath, this.SHARED_PLAYLISTS_FOLDER); } + + } \ No newline at end of file diff --git a/src/main/services/maps/local-maps-manager.service.ts b/src/main/services/maps/local-maps-manager.service.ts new file mode 100644 index 00000000..f50531cc --- /dev/null +++ b/src/main/services/maps/local-maps-manager.service.ts @@ -0,0 +1,91 @@ +import path from "path"; +import { BSVersion } from "shared/bs-version.interface"; +import { RawMapInfoData } from "shared/models/maps"; +import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"; +import { BSLocalVersionService } from "../bs-local-version.service"; +import { InstallationLocationService } from "../installation-location.service"; +import { UtilsService } from "../utils.service"; +import crypto from "crypto"; + +export class LocalMapsManagerService { + + private static instance: LocalMapsManagerService; + + public static getInstance(): LocalMapsManagerService{ + if(!LocalMapsManagerService.instance){ LocalMapsManagerService.instance = new LocalMapsManagerService(); } + return LocalMapsManagerService.instance; + } + + private readonly LEVELS_ROOT_FOLDER = "Beat Saber_Data"; + private readonly CUSTOM_LEVELS_FOLDER = "CustomLevels"; + private readonly WIP_LEVELS_FOLDER = "CustomWIPLevels"; + + private readonly localVersion: BSLocalVersionService; + private readonly installLocation: InstallationLocationService; + private readonly utils: UtilsService; + + private constructor(){ + this.localVersion = BSLocalVersionService.getInstance(); + this.installLocation = InstallationLocationService.getInstance(); + this.utils = UtilsService.getInstance(); + } + + private async getMapsPath(version?: BSVersion): Promise{ + if(version){ return path.join(await this.localVersion.getVersionPath(version), this.LEVELS_ROOT_FOLDER); } + return this.installLocation.sharedMapsPath; + } + + private async computeMapHash(mapPath: string, rawInfoString: string): Promise{ + const mapRawInfo = JSON.parse(rawInfoString); + let content = rawInfoString; + console.log("oui"); + for(const set of mapRawInfo._difficultyBeatmapSets){ + for(const diff of set._difficultyBeatmaps){ + const diffFilePath = path.join(mapPath, diff._beatmapFilename); + if(!await this.utils.pathExist(diffFilePath)){ continue; } + const diffContent = (await this.utils.readFileAsync(diffFilePath)).toString() + content += diffContent; + } + } + + const shasum = crypto.createHash("sha1"); + shasum.update(content); + return shasum.digest("hex"); + } + + private async loadMapInfoFromPath(mapPath: string): Promise{ + const infoFilePath = path.join(mapPath, "Info.dat"); + + if(!(await this.utils.pathExist(infoFilePath))){ return null; } + + const rawInfoString = await (await (this.utils.readFileAsync(infoFilePath))).toString(); + + const rawInfo: RawMapInfoData = JSON.parse(rawInfoString); + const coverUrl = new URL(`file:///${path.join(mapPath, rawInfo._coverImageFilename)}`).href; + const songUrl = new URL(`file:///${path.join(mapPath, rawInfo._songFilename)}`).href; + + const hash = await this.computeMapHash(mapPath, rawInfoString); + + return {rawInfo, coverUrl, songUrl, hash}; + } + + public async getMaps(version?: BSVersion): Promise{ + const levelsRoot = await this.getMapsPath(version); + const levelsFolder = path.join(levelsRoot, this.CUSTOM_LEVELS_FOLDER); + + const levelsPath = (await this.utils.pathExist(levelsFolder)) ? this.utils.listDirsInDir(levelsFolder, true) : []; + + + + const mapsInfo = await Promise.all(levelsPath.map(levelPath => this.loadMapInfoFromPath(levelPath))) + + console.log(mapsInfo); + + return mapsInfo.filter(info => !!info); + } + + public deleteMap(version?: BSVersion){ + + } + +} \ No newline at end of file diff --git a/src/main/services/utils.service.ts b/src/main/services/utils.service.ts index 328a9ac7..62600de9 100644 --- a/src/main/services/utils.service.ts +++ b/src/main/services/utils.service.ts @@ -68,10 +68,10 @@ export class UtilsService{ }); } - public listDirsInDir(dirPath: string): string[]{ + public listDirsInDir(dirPath: string, fullPath = false): string[]{ let files = readdirSync(dirPath, { withFileTypes:true}); files = files.filter(f => f.isDirectory()) - return files.map(f => f.name); + return files.map(f => fullPath ? path.join(dirPath, f.name) : f.name); } public deleteFolder(folderPath: string): Promise{ diff --git a/src/renderer/components/available-versions/available-versions-slide.component.tsx b/src/renderer/components/available-versions/available-versions-slide.component.tsx index ecfc970e..5cbb3484 100644 --- a/src/renderer/components/available-versions/available-versions-slide.component.tsx +++ b/src/renderer/components/available-versions/available-versions-slide.component.tsx @@ -16,10 +16,6 @@ export function AvailableVersionsSlide(props: {year: string}) { }); }, []) -//w-full max-w-full max-h-full flex items-start justify-center overflow-x-hidden overflow-y-scroll content-start scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900 - -//relative left-[2px] flex justify-center items-start content-start flex-wrap max-w-6xl - return (
    {availableVersions.map((version, index) => diff --git a/src/renderer/components/available-versions/available-versions-slider.component.tsx b/src/renderer/components/available-versions/available-versions-slider.component.tsx index aa5d1250..01bf8fe7 100644 --- a/src/renderer/components/available-versions/available-versions-slider.component.tsx +++ b/src/renderer/components/available-versions/available-versions-slider.component.tsx @@ -25,8 +25,8 @@ export function AvailableVersionsSlider() {
      - { availableYears.map((year, index) => - + { availableYears.map(year => + )}
    diff --git a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx index 2883585e..4b0e3047 100644 --- a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx +++ b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx @@ -1,25 +1,35 @@ import { useState } from "react" +import { useObservable } from "renderer/hooks/use-observable.hook" import { MapsManagerService } from "renderer/services/maps-manager.service" import { BSVersion } from "shared/bs-version.interface" import { TabNavBar } from "../shared/tab-nav-bar.component" type Props = { + oneBlock?: boolean, version?: BSVersion } -export function MapsPlaylistsPanel({version}: Props) { +export function MapsPlaylistsPanel({version, oneBlock = false}: Props) { + const mapsManager = MapsManagerService.getInstance(); + const [tabIndex, setTabIndex] = useState(0); + const maps = useObservable(mapsManager.getMaps(version)); - console.log(tabIndex); + console.log(maps); return ( + <> + {!oneBlock && }
    - -
    -
    a
    -
    b
    + {oneBlock && } +
    +
    + a +
    +
    b
    + ) } diff --git a/src/renderer/helpers/array-tools.ts b/src/renderer/helpers/array-tools.ts new file mode 100644 index 00000000..e7967792 --- /dev/null +++ b/src/renderer/helpers/array-tools.ts @@ -0,0 +1,7 @@ +export function splitIntoChunk(arr: T[], chunkSize: number): T[][] { + const resArr = []; + for(let i = 0; i < arr.length; i += chunkSize){ + resArr.push(arr.slice(i, i + chunkSize)); + } + return resArr; +} \ No newline at end of file diff --git a/src/renderer/pages/available-versions-list.components.tsx b/src/renderer/pages/available-versions-list.components.tsx index bb37998c..29ebefdb 100644 --- a/src/renderer/pages/available-versions-list.components.tsx +++ b/src/renderer/pages/available-versions-list.components.tsx @@ -35,7 +35,7 @@ export function AvailableVersionsList() { return (
    - +

    {t("pages.available-versions.title")}

    diff --git a/src/renderer/pages/maps-page.component.tsx b/src/renderer/pages/maps-page.component.tsx index 3e24987c..77aba182 100644 --- a/src/renderer/pages/maps-page.component.tsx +++ b/src/renderer/pages/maps-page.component.tsx @@ -5,8 +5,8 @@ export default function MapsPage() { return (
    -

    Maps partagées

    -
    +

    Maps partagées

    +
    diff --git a/src/renderer/services/beat-saver.service.ts b/src/renderer/services/beat-saver.service.ts new file mode 100644 index 00000000..f3c7a217 --- /dev/null +++ b/src/renderer/services/beat-saver.service.ts @@ -0,0 +1,18 @@ +import { BsvMapDetail } from "shared/models/maps"; + +export class BeatSaverService { + + private static instance: BeatSaverService; + + public static getInstance(): BeatSaverService{ + if(!BeatSaverService.instance){ BeatSaverService.instance = new BeatSaverService(); } + return BeatSaverService.instance; + } + + private constructor(){} + + public getMapDetailsFromHashs(hashs: string[]): BsvMapDetail{ + return null; + } + +} \ No newline at end of file diff --git a/src/renderer/services/maps-manager.service.ts b/src/renderer/services/maps-manager.service.ts index 41378cbe..0dcbe73f 100644 --- a/src/renderer/services/maps-manager.service.ts +++ b/src/renderer/services/maps-manager.service.ts @@ -1,4 +1,7 @@ +import { Observable } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; +import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"; +import { IpcService } from "./ipc.service"; export class MapsManagerService { @@ -9,12 +12,19 @@ export class MapsManagerService { return MapsManagerService.instance; } - private constructor(){ + private readonly ipcService: IpcService; + private constructor(){ + this.ipcService = IpcService.getInstance(); } - public getMaps(version?: BSVersion): any[]{ - return []; + public getMaps(version?: BSVersion): Observable{ + return new Observable(obs => { + this.ipcService.send("get-version-maps", {args: version}).then(res => { + if(!res.success){ return obs.next(null);} + obs.next(res.data); + }); + }); } public downloadMap(map: any, version?: BSVersion){ diff --git a/src/shared/models/maps/index.ts b/src/shared/models/maps/index.ts new file mode 100644 index 00000000..c126f53c --- /dev/null +++ b/src/shared/models/maps/index.ts @@ -0,0 +1,15 @@ +export { RawMapInfoData, RawMapDifficulty, RawDifficultySet } from "./raw-map.model"; + +export { ExportVersionMapsOption } from "./export-version-maps.model"; + +export { + BsvInstant, + BsvMapDetail, + BsvMapDetailMetadata, + BsvMapDifficulty, + BsvMapParitySummary, + BsvMapStats, + BsvMapTestplay, + BsvMapVersion, + BsvUserDetail +} from "./beat-saver.model"; \ No newline at end of file