diff --git a/apps/frontend/src/components/ui/create-project-version/CreateProjectVersionModal.vue b/apps/frontend/src/components/ui/create-project-version/CreateProjectVersionModal.vue index 8ab178c7..98fa4f86 100644 --- a/apps/frontend/src/components/ui/create-project-version/CreateProjectVersionModal.vue +++ b/apps/frontend/src/components/ui/create-project-version/CreateProjectVersionModal.vue @@ -22,7 +22,7 @@ const modal = useTemplateRef>('modal') const ctx = createManageVersionContext(modal) provideManageVersionContext(ctx) -const { newDraftVersion, setProjectType } = ctx +const { newDraftVersion } = ctx const { projectV2 } = injectProjectPageContext() const { addNotification } = injectNotificationManager() @@ -62,7 +62,6 @@ function openCreateVersionModal( stageId: string | null = null, ) { newDraftVersion(projectV2.value.id, version) - setProjectType(projectV2.value) modal.value?.setStage(stageId ?? 0) modal.value?.show() } diff --git a/apps/frontend/src/components/ui/create-project-version/stages/AddFilesStage.vue b/apps/frontend/src/components/ui/create-project-version/stages/AddFilesStage.vue index bafd30ed..f257a76e 100644 --- a/apps/frontend/src/components/ui/create-project-version/stages/AddFilesStage.vue +++ b/apps/frontend/src/components/ui/create-project-version/stages/AddFilesStage.vue @@ -103,9 +103,7 @@ const { existingFilesToDelete, setPrimaryFile, setInferredVersionData, - setProjectType, editingVersion, - projectType, } = injectManageVersionContext() const addDetectedData = async () => { @@ -125,17 +123,9 @@ const addDetectedData = async () => { ...draftVersion.value, ...mappedInferredData, } - - setProjectType(projectV2.value, primaryFile) } catch (err) { console.error('Error parsing version file data', err) } - - if (projectType.value === 'resourcepack') { - draftVersion.value.loaders = ['minecraft'] - } else if (projectType.value === 'modpack' && draftVersion.value.loaders?.length === 0) { - draftVersion.value.loaders = ['minecraft'] - } } // add detected data when the primary file changes diff --git a/apps/frontend/src/components/ui/create-project-version/stages/AddLoadersStage.vue b/apps/frontend/src/components/ui/create-project-version/stages/AddLoadersStage.vue index 0fe100ad..ce8d9230 100644 --- a/apps/frontend/src/components/ui/create-project-version/stages/AddLoadersStage.vue +++ b/apps/frontend/src/components/ui/create-project-version/stages/AddLoadersStage.vue @@ -42,7 +42,7 @@ diff --git a/apps/frontend/src/providers/version/manage-version-modal.ts b/apps/frontend/src/providers/version/manage-version-modal.ts index 4247edf1..c5ad6ab0 100644 --- a/apps/frontend/src/providers/version/manage-version-modal.ts +++ b/apps/frontend/src/providers/version/manage-version-modal.ts @@ -86,10 +86,6 @@ export interface ManageVersionContextValue { file: File, project: Labrinth.Projects.v2.Project, ) => Promise - setProjectType: ( - project: Labrinth.Projects.v2.Project, - file?: File | null, - ) => Promise getProject: (projectId: string) => Promise getVersion: (versionId: string) => Promise @@ -98,6 +94,41 @@ export interface ManageVersionContextValue { handleSaveVersionEdits: () => Promise } +const PROJECT_TYPE_LOADERS: Record = { + mod: [ + 'fabric', + 'neoforge', + 'forge', + 'quilt', + 'liteloader', + 'rift', + 'ornithe', + 'nilloader', + 'risugami', + 'legacy-fabric', + 'bta-babric', + 'babric', + 'modloader', + 'java-agent', + ], + shader: ['optifine', 'iris', 'canvas', 'vanilla'], + plugin: [ + 'paper', + 'purpur', + 'spigot', + 'bukkit', + 'sponge', + 'folia', + 'bungeecord', + 'velocity', + 'waterfall', + 'geyser', + ], + datapack: ['datapack'], + resourcepack: ['minecraft'], + modpack: ['mrpack'], +} as const + export const [injectManageVersionContext, provideManageVersionContext] = createContext('CreateProjectVersionModal') @@ -113,80 +144,47 @@ export function createManageVersionContext( const filesToAdd = ref([]) const existingFilesToDelete = ref([]) const inferredVersionData = ref() - const projectType = ref() const dependencyProjects = ref>({}) const dependencyVersions = ref>({}) const isSubmitting = ref(false) + const projectType = computed(() => { + const primaryFile = filesToAdd.value[0]?.file + if ( + (primaryFile && primaryFile.name.toLowerCase().endsWith('.mrpack')) || + (primaryFile && primaryFile.name.toLowerCase().endsWith('.mrpack-primary')) + ) { + return 'modpack' + } + + const loaders = draftVersion.value.loaders || [] + + if (loaders.some((loader) => PROJECT_TYPE_LOADERS.modpack.includes(loader))) { + return 'modpack' + } + + if (loaders.some((loader) => PROJECT_TYPE_LOADERS.datapack.includes(loader))) { + return 'datapack' + } + if (loaders.some((loader) => PROJECT_TYPE_LOADERS.resourcepack.includes(loader))) { + return 'resourcepack' + } + if (loaders.some((loader) => PROJECT_TYPE_LOADERS.shader.includes(loader))) { + return 'shader' + } + if (loaders.some((loader) => PROJECT_TYPE_LOADERS.plugin.includes(loader))) { + return 'plugin' + } + if (loaders.some((loader) => PROJECT_TYPE_LOADERS.mod.includes(loader))) { + return 'mod' + } + + return 'project' + }) + // Computed state const editingVersion = computed(() => Boolean(draftVersion.value.version_id)) - // Helper functions for project type detection - // TODO: move to infer.js - async function setProjectType( - project: Labrinth.Projects.v2.Project, - file: File | null = null, - ): Promise { - if (project.project_type && project.project_type !== 'project') { - projectType.value = project.project_type - return projectType.value - } - - if ( - (file && file.name.toLowerCase().endsWith('.mrpack')) || - (file && file.name.toLowerCase().endsWith('.mrpack-primary')) - ) { - projectType.value = 'modpack' - return projectType.value - } - - if ( - draftVersion.value.loaders?.some((loader) => - [ - 'fabric', - 'neoforge', - 'forge', - 'quilt', - 'liteloader', - 'rift', - 'ornithe', - 'nilloader', - 'legacy-fabric', - 'bta-babric', - 'babric', - 'modloader', - 'java-agent', - ].includes(loader), - ) - ) { - projectType.value = 'mod' - return projectType.value - } - - try { - if (file) { - const jszip = await JSZip.loadAsync(file) - - const hasMcmeta = Object.keys(jszip.files).some( - (f) => f.toLowerCase() === 'pack.mcmeta' || f.toLowerCase().endsWith('/pack.mcmeta'), - ) - const hasAssetsDir = Object.keys(jszip.files).some( - (f) => f.toLowerCase() === 'assets/' || f.toLowerCase().startsWith('assets/'), - ) - - if (hasMcmeta && hasAssetsDir) { - projectType.value = 'resourcepack' - return projectType.value - } - } - } catch { - // not a zip - } - - projectType.value = undefined - return undefined - } - // Version management methods function newDraftVersion( projectId: string, @@ -197,7 +195,7 @@ export function createManageVersionContext( filesToAdd.value = [] existingFilesToDelete.value = [] inferredVersionData.value = undefined - projectType.value = undefined + // projectType.value = undefined } function setPrimaryFile(index: number) { @@ -210,6 +208,33 @@ export function createManageVersionContext( const tags = useGeneratedState() + const hasFile = (entries: string[], name: string) => + entries.some((f) => f === name || f.endsWith(`/${name}`)) + + const hasDir = (entries: string[], dir: string) => entries.some((f) => f.startsWith(`${dir}/`)) + + async function checkIsResourcePack(file: File): Promise { + try { + const zip = await JSZip.loadAsync(file) + const entries = Object.keys(zip.files).map((f) => f.toLowerCase()) + + return hasFile(entries, 'pack.mcmeta') && hasDir(entries, 'assets') + } catch { + return false + } + } + + async function checkIsDataPack(file: File): Promise { + try { + const zip = await JSZip.loadAsync(file) + const entries = Object.keys(zip.files).map((f) => f.toLowerCase()) + + return hasFile(entries, 'pack.mcmeta') && hasDir(entries, 'data') + } catch { + return false + } + } + async function setInferredVersionData( file: File, project: Labrinth.Projects.v2.Project, @@ -234,8 +259,21 @@ export function createManageVersionContext( console.error('Error fetching versions for environment inference:', error) } + const noLoaders = !inferred.loaders?.length + + if (noLoaders && (await checkIsResourcePack(file))) { + inferred.loaders = ['minecraft'] + } + + if (noLoaders && (await checkIsDataPack(file))) { + inferred.loaders = ['datapack'] + } + + if (noLoaders && projectType.value === 'modpack') { + inferred.loaders = ['minecraft'] + } + inferredVersionData.value = inferred - projectType.value = await setProjectType(project, file) return inferred } @@ -423,7 +461,6 @@ export function createManageVersionContext( newDraftVersion, setPrimaryFile, setInferredVersionData, - setProjectType, getProject, getVersion, handleCreateVersion,