diff --git a/package-lock.json b/package-lock.json index cbb35b4c..f8d63bdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -994,16 +994,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@laupetin/vite-plugin-cpp-header": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@laupetin/vite-plugin-cpp-header/-/vite-plugin-cpp-header-1.1.0.tgz", - "integrity": "sha512-nUf5yTkL+oy7VxdTOe6jpx3juZksMI7f+zpA9Ns7PSAB+0vcXAa5wtkdFfbn93HaBc2QI3hJZmdfOzsCihD3Ow==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "vite": ">=7.0.0" - } - }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -2687,6 +2677,23 @@ } } }, + "node_modules/@webwindowed/vite-plugin-cpp-header": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@webwindowed/vite-plugin-cpp-header/-/vite-plugin-cpp-header-1.0.0.tgz", + "integrity": "sha512-0eALUR+M6rkq45FXslE36/UJWZ2Xy9Gt+JH1GNINnlp9QH+JP7wBqp228+bUHuSxgGIiSXsSQi3C0CA+AbmxRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": ">=7.0.0" + } + }, + "node_modules/@webwindowed/web-api": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@webwindowed/web-api/-/web-api-1.0.0.tgz", + "integrity": "sha512-/vshvMK/ApurI2Rapt5RsbhuFQZZ+IyhhSd2Plvm39otxg+DTSN6kLoiOhTTmT1rG2QNBZKvQ7f2BLjwzXF1hQ==", + "dev": true, + "license": "MIT" + }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", @@ -6883,7 +6890,6 @@ "vue-router": "5.1.0" }, "devDependencies": { - "@laupetin/vite-plugin-cpp-header": "1.1.0", "@tsconfig/node24": "24.0.4", "@types/jsdom": "28.0.3", "@types/node": "25.9.2", @@ -6893,6 +6899,8 @@ "@vue/eslint-config-typescript": "14.8.0", "@vue/test-utils": "2.4.11", "@vue/tsconfig": "0.9.1", + "@webwindowed/vite-plugin-cpp-header": "1.0.0", + "@webwindowed/web-api": "1.0.0", "eslint": "10.4.1", "eslint-plugin-vue": "10.9.2", "jiti": "2.7.0", diff --git a/src/ModManUi/.prettierignore b/src/ModManUi/.prettierignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/src/ModManUi/.prettierignore @@ -0,0 +1 @@ +dist diff --git a/src/ModManUi/package.json b/src/ModManUi/package.json index 8991dd2d..17bed55c 100644 --- a/src/ModManUi/package.json +++ b/src/ModManUi/package.json @@ -22,7 +22,6 @@ "vue-router": "5.1.0" }, "devDependencies": { - "@laupetin/vite-plugin-cpp-header": "1.1.0", "@tsconfig/node24": "24.0.4", "@types/jsdom": "28.0.3", "@types/node": "25.9.2", @@ -32,6 +31,8 @@ "@vue/eslint-config-typescript": "14.8.0", "@vue/test-utils": "2.4.11", "@vue/tsconfig": "0.9.1", + "@webwindowed/vite-plugin-cpp-header": "1.0.0", + "@webwindowed/web-api": "1.0.0", "eslint": "10.4.1", "eslint-plugin-vue": "10.9.2", "jiti": "2.7.0", diff --git a/src/ModManUi/src/native/AssetBinds.ts b/src/ModManUi/src/native/AssetBinds.ts index ce8a2f6c..9b286056 100644 --- a/src/ModManUi/src/native/AssetBinds.ts +++ b/src/ModManUi/src/native/AssetBinds.ts @@ -1,3 +1,5 @@ +import { getBinds } from "@webwindowed/web-api"; + export enum CommonAssetType { PHYS_PRESET = "PHYS_PRESET", XANIM = "XANIM", @@ -84,6 +86,8 @@ export interface ZoneAssetsDto { references: AssetDto[]; } -export interface AssetBinds { +type AssetBinds = { getAssetsForZone(zoneName: string): Promise; -} +}; + +export const { getAssetsForZone } = getBinds(); diff --git a/src/ModManUi/src/native/DialogBinds.ts b/src/ModManUi/src/native/DialogBinds.ts index 97ddce0b..210ef9c7 100644 --- a/src/ModManUi/src/native/DialogBinds.ts +++ b/src/ModManUi/src/native/DialogBinds.ts @@ -1,3 +1,5 @@ +import { getBinds } from "@webwindowed/web-api"; + export interface FileDialogFilterDto { name: string; filter: string; @@ -11,8 +13,10 @@ export interface SaveFileDialogDto { filters?: FileDialogFilterDto[]; } -export interface DialogBinds { +type DialogBinds = { openFileDialog(options?: OpenFileDialogDto): Promise; saveFileDialog(options?: SaveFileDialogDto): Promise; folderSelectDialog(): Promise; -} +}; + +export const { openFileDialog, saveFileDialog, folderSelectDialog } = getBinds(); diff --git a/src/ModManUi/src/native/Events.ts b/src/ModManUi/src/native/Events.ts new file mode 100644 index 00000000..43483a06 --- /dev/null +++ b/src/ModManUi/src/native/Events.ts @@ -0,0 +1,6 @@ +import { getEvents } from "@webwindowed/web-api"; +import type { UnlinkingEventMap } from "@/native/UnlinkingBinds.ts"; +import type { ZoneEventMap } from "@/native/ZoneBinds.ts"; + +type NativeEventMap = UnlinkingEventMap & ZoneEventMap; +export const { addEventListener, removeEventListener } = getEvents(); diff --git a/src/ModManUi/src/native/UnlinkingBinds.ts b/src/ModManUi/src/native/UnlinkingBinds.ts index 838282ca..602bdfbb 100644 --- a/src/ModManUi/src/native/UnlinkingBinds.ts +++ b/src/ModManUi/src/native/UnlinkingBinds.ts @@ -1,3 +1,5 @@ +import { getBinds } from "@webwindowed/web-api"; + export interface ZoneUnlinkProgressDto { zoneName: string; /** @@ -6,10 +8,12 @@ export interface ZoneUnlinkProgressDto { percentage: number; } -export interface UnlinkingBinds { +type UnlinkingBinds = { unlinkZone(zoneName: string): Promise; -} +}; -export interface UnlinkingEventMap { +export type UnlinkingEventMap = { zoneUnlinkProgress: ZoneUnlinkProgressDto; -} +}; + +export const { unlinkZone } = getBinds(); diff --git a/src/ModManUi/src/native/ZoneBinds.ts b/src/ModManUi/src/native/ZoneBinds.ts index 19b5693f..ab306c59 100644 --- a/src/ModManUi/src/native/ZoneBinds.ts +++ b/src/ModManUi/src/native/ZoneBinds.ts @@ -1,3 +1,5 @@ +import { getBinds } from "@webwindowed/web-api"; + export enum GameId { IW3 = "IW3", IW4 = "IW4", @@ -36,14 +38,16 @@ export interface ZoneUnloadedDto { zoneName: string; } -export interface ZoneBinds { +type ZoneBinds = { getZones(): Promise; loadFastFile(path: string): Promise; unloadZone(zoneName: string): Promise; -} +}; -export interface ZoneEventMap { +export type ZoneEventMap = { zoneLoadProgress: ZoneLoadProgressDto; zoneLoaded: ZoneLoadedDto; zoneUnloaded: ZoneUnloadedDto; -} +}; + +export const { getZones, loadFastFile, unloadZone } = getBinds(); diff --git a/src/ModManUi/src/native/index.ts b/src/ModManUi/src/native/index.ts deleted file mode 100644 index a6378d25..00000000 --- a/src/ModManUi/src/native/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { AssetBinds } from "./AssetBinds"; -import type { DialogBinds } from "./DialogBinds"; -import type { UnlinkingBinds, UnlinkingEventMap } from "./UnlinkingBinds"; -import type { ZoneBinds, ZoneEventMap } from "./ZoneBinds"; - -export type NativeMethods = AssetBinds & DialogBinds & UnlinkingBinds & ZoneBinds; - -type NativeEventMap = UnlinkingEventMap & ZoneEventMap; - -type WebWindowedExtensions = { - webwindowedBinds: NativeMethods; - webwindowedAddEventListener( - eventKey: K, - callback: (payload: NativeEventMap[K]) => void, - ): void; - webwindowedRemoveEventListener( - eventKey: K, - callback: (payload: NativeEventMap[K]) => void, - ): boolean; -}; - -const windowWithWebWindowedExtensions = window as typeof window & WebWindowedExtensions; - -export const webwindowedBinds = windowWithWebWindowedExtensions.webwindowedBinds; -export const webwindowedAddEventListener = - windowWithWebWindowedExtensions.webwindowedAddEventListener; -export const webwindowedRemoveEventListener = - windowWithWebWindowedExtensions.webwindowedRemoveEventListener; diff --git a/src/ModManUi/src/stores/AssetStore.ts b/src/ModManUi/src/stores/AssetStore.ts index b8755d7f..e6ed48a0 100644 --- a/src/ModManUi/src/stores/AssetStore.ts +++ b/src/ModManUi/src/stores/AssetStore.ts @@ -1,7 +1,6 @@ import { computed, ref } from "vue"; import { defineStore } from "pinia"; -import type { ZoneAssetsDto } from "@/native/AssetBinds"; -import { webwindowedBinds } from "@/native"; +import { getAssetsForZone, type ZoneAssetsDto } from "@/native/AssetBinds"; export const useAssetStore = defineStore("asset", () => { const zoneName = ref(null); @@ -21,7 +20,7 @@ export const useAssetStore = defineStore("asset", () => { // Only load assets when there is a new zone name specified if (!newZoneName) return; - webwindowedBinds.getAssetsForZone(newZoneName).then((res) => { + getAssetsForZone(newZoneName).then((res) => { if (zoneName.value === newZoneName) { assetsOfZone.value = res; } diff --git a/src/ModManUi/src/stores/UnlinkingStore.ts b/src/ModManUi/src/stores/UnlinkingStore.ts index d178ffad..73e52434 100644 --- a/src/ModManUi/src/stores/UnlinkingStore.ts +++ b/src/ModManUi/src/stores/UnlinkingStore.ts @@ -1,6 +1,7 @@ import { ref } from "vue"; import { defineStore } from "pinia"; -import { webwindowedAddEventListener, webwindowedBinds } from "@/native"; +import { addEventListener } from "@/native/Events.ts"; +import { unlinkZone as nativeUnlinkZone } from "@/native/UnlinkingBinds.ts"; export const useUnlinkingStore = defineStore("unlinking", () => { const isUnlinking = ref(false); @@ -11,8 +12,8 @@ export const useUnlinkingStore = defineStore("unlinking", () => { isUnlinking.value = true; lastPercentage.value = 0; failureMessage.value = null; - return webwindowedBinds - .unlinkZone(zoneName) + + return nativeUnlinkZone(zoneName) .catch((e: string) => { console.error("Failed to unlink fastfile:", e); failureMessage.value = e; @@ -23,7 +24,7 @@ export const useUnlinkingStore = defineStore("unlinking", () => { }); } - webwindowedAddEventListener("zoneUnlinkProgress", (dto) => { + addEventListener("zoneUnlinkProgress", (dto) => { lastPercentage.value = dto.percentage; }); diff --git a/src/ModManUi/src/stores/ZoneStore.ts b/src/ModManUi/src/stores/ZoneStore.ts index 0d9e7d26..0a7bed13 100644 --- a/src/ModManUi/src/stores/ZoneStore.ts +++ b/src/ModManUi/src/stores/ZoneStore.ts @@ -1,7 +1,12 @@ import { computed, ref } from "vue"; import { defineStore } from "pinia"; -import { webwindowedAddEventListener, webwindowedBinds } from "@/native"; -import type { ZoneDto, ZoneLoadedDto } from "@/native/ZoneBinds"; +import { + getZones, + loadFastFile as nativeLoadFastFile, + type ZoneDto, + type ZoneLoadedDto, +} from "@/native/ZoneBinds"; +import { addEventListener } from "@/native/Events.ts"; export const useZoneStore = defineStore("zone", () => { const loadedZones = ref([]); @@ -21,8 +26,7 @@ export const useZoneStore = defineStore("zone", () => { zonesCurrentlyBeingLoaded.value.push(expectedZoneName); lastPercentageByZoneName.value[expectedZoneName] = 0; - return webwindowedBinds - .loadFastFile(fastFilePath) + return nativeLoadFastFile(fastFilePath) .catch((e: string) => { console.error("Failed to load fastfile:", e); }) @@ -44,21 +48,21 @@ export const useZoneStore = defineStore("zone", () => { } // Initially get all loaded zones - webwindowedBinds.getZones().then((allZones) => { + getZones().then((allZones) => { loadedZones.value = allZones; }); - webwindowedAddEventListener("zoneLoadProgress", (dto) => { + addEventListener("zoneLoadProgress", (dto) => { if (lastPercentageByZoneName.value[dto.zoneName] !== undefined) { lastPercentageByZoneName.value[dto.zoneName] = dto.percentage; } }); - webwindowedAddEventListener("zoneLoaded", (dto) => { + addEventListener("zoneLoaded", (dto) => { loadedZones.value.push(dto.zone); }); - webwindowedAddEventListener("zoneUnloaded", (dto) => { + addEventListener("zoneUnloaded", (dto) => { const index = loadedZones.value.findIndex((zone) => zone.name === dto.zoneName); if (index >= 0) { loadedZones.value.splice(index, 1); diff --git a/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue b/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue index 02d2c51e..eaa523a8 100644 --- a/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue +++ b/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue @@ -4,7 +4,8 @@ import ProgressBar from "primevue/progressbar"; import Listbox from "primevue/listbox"; import { computed } from "vue"; import { useZoneStore } from "@/stores/ZoneStore"; -import { webwindowedBinds } from "@/native"; +import { openFileDialog } from "@/native/DialogBinds.ts"; +import { unloadZone } from "@/native/ZoneBinds.ts"; interface SelectableZone { isLoading: boolean; @@ -15,7 +16,7 @@ const zoneStore = useZoneStore(); const selectedZone = defineModel("selectedZone"); async function openFastFileSelect() { - return await webwindowedBinds.openFileDialog({ + return await openFileDialog({ filters: [{ name: "Fastfiles", filter: "*.ff" }], }); } @@ -53,7 +54,7 @@ const availableZones = computed(() => { function onUnloadClicked() { if (!selectedZone.value) return; - webwindowedBinds.unloadZone(selectedZone.value).catch((e: string) => { + unloadZone(selectedZone.value).catch((e: string) => { console.error("Failed to unload zone:", e); }); } diff --git a/src/ModManUi/vite.config.ts b/src/ModManUi/vite.config.ts index 5b0b15e1..fbd96da4 100644 --- a/src/ModManUi/vite.config.ts +++ b/src/ModManUi/vite.config.ts @@ -3,7 +3,7 @@ import { fileURLToPath, URL } from "node:url"; import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import vueDevTools from "vite-plugin-vue-devtools"; -import PluginCppHeader from "@laupetin/vite-plugin-cpp-header"; +import PluginCppHeader from "@webwindowed/vite-plugin-cpp-header"; // https://vite.dev/config/ export default defineConfig({