@@ -86,10 +86,6 @@ export interface ManageVersionContextValue {
8686 file : File ,
8787 project : Labrinth . Projects . v2 . Project ,
8888 ) => Promise < InferredVersionInfo >
89- setProjectType : (
90- project : Labrinth . Projects . v2 . Project ,
91- file ?: File | null ,
92- ) => Promise < Labrinth . Projects . v2 . ProjectType | undefined >
9389 getProject : ( projectId : string ) => Promise < Labrinth . Projects . v3 . Project >
9490 getVersion : ( versionId : string ) => Promise < Labrinth . Versions . v3 . Version >
9591
@@ -98,6 +94,41 @@ export interface ManageVersionContextValue {
9894 handleSaveVersionEdits : ( ) => Promise < void >
9995}
10096
97+ const PROJECT_TYPE_LOADERS : Record < string , readonly string [ ] > = {
98+ mod : [
99+ 'fabric' ,
100+ 'neoforge' ,
101+ 'forge' ,
102+ 'quilt' ,
103+ 'liteloader' ,
104+ 'rift' ,
105+ 'ornithe' ,
106+ 'nilloader' ,
107+ 'risugami' ,
108+ 'legacy-fabric' ,
109+ 'bta-babric' ,
110+ 'babric' ,
111+ 'modloader' ,
112+ 'java-agent' ,
113+ ] ,
114+ shader : [ 'optifine' , 'iris' , 'canvas' , 'vanilla' ] ,
115+ plugin : [
116+ 'paper' ,
117+ 'purpur' ,
118+ 'spigot' ,
119+ 'bukkit' ,
120+ 'sponge' ,
121+ 'folia' ,
122+ 'bungeecord' ,
123+ 'velocity' ,
124+ 'waterfall' ,
125+ 'geyser' ,
126+ ] ,
127+ datapack : [ 'datapack' ] ,
128+ resourcepack : [ 'minecraft' ] ,
129+ modpack : [ 'mrpack' ] ,
130+ } as const
131+
101132export const [ injectManageVersionContext , provideManageVersionContext ] =
102133 createContext < ManageVersionContextValue > ( 'CreateProjectVersionModal' )
103134
@@ -113,79 +144,46 @@ export function createManageVersionContext(
113144 const filesToAdd = ref < Labrinth . Versions . v3 . DraftVersionFile [ ] > ( [ ] )
114145 const existingFilesToDelete = ref < Labrinth . Versions . v3 . VersionFileHash [ 'sha1' ] [ ] > ( [ ] )
115146 const inferredVersionData = ref < InferredVersionInfo > ( )
116- const projectType = ref < Labrinth . Projects . v2 . ProjectType > ( )
117147 const dependencyProjects = ref < Record < string , Labrinth . Projects . v3 . Project > > ( { } )
118148 const dependencyVersions = ref < Record < string , Labrinth . Versions . v3 . Version > > ( { } )
119149 const isSubmitting = ref ( false )
120150
121- // Computed state
122- const editingVersion = computed ( ( ) => Boolean ( draftVersion . value . version_id ) )
123-
124- // Helper functions for project type detection
125- // TODO: move to infer.js
126- async function setProjectType (
127- project : Labrinth . Projects . v2 . Project ,
128- file : File | null = null ,
129- ) : Promise < Labrinth . Projects . v2 . ProjectType | undefined > {
130- if ( project . project_type && project . project_type !== 'project' ) {
131- projectType . value = project . project_type
132- return projectType . value
133- }
134-
151+ const projectType = computed < Labrinth . Projects . v2 . ProjectType > ( ( ) => {
152+ const primaryFile = filesToAdd . value [ 0 ] ?. file
135153 if (
136- ( file && file . name . toLowerCase ( ) . endsWith ( '.mrpack' ) ) ||
137- ( file && file . name . toLowerCase ( ) . endsWith ( '.mrpack-primary' ) )
154+ ( primaryFile && primaryFile . name . toLowerCase ( ) . endsWith ( '.mrpack' ) ) ||
155+ ( primaryFile && primaryFile . name . toLowerCase ( ) . endsWith ( '.mrpack-primary' ) )
138156 ) {
139- projectType . value = 'modpack'
140- return projectType . value
157+ return 'modpack'
141158 }
142159
143- if (
144- draftVersion . value . loaders ?. some ( ( loader ) =>
145- [
146- 'fabric' ,
147- 'neoforge' ,
148- 'forge' ,
149- 'quilt' ,
150- 'liteloader' ,
151- 'rift' ,
152- 'ornithe' ,
153- 'nilloader' ,
154- 'legacy-fabric' ,
155- 'bta-babric' ,
156- 'babric' ,
157- 'modloader' ,
158- 'java-agent' ,
159- ] . includes ( loader ) ,
160- )
161- ) {
162- projectType . value = 'mod'
163- return projectType . value
160+ const loaders = draftVersion . value . loaders || [ ]
161+
162+ if ( loaders . some ( ( loader ) => PROJECT_TYPE_LOADERS . modpack . includes ( loader ) ) ) {
163+ return 'modpack'
164164 }
165165
166- try {
167- if ( file ) {
168- const jszip = await JSZip . loadAsync ( file )
169-
170- const hasMcmeta = Object . keys ( jszip . files ) . some (
171- ( f ) => f . toLowerCase ( ) === 'pack.mcmeta' || f . toLowerCase ( ) . endsWith ( '/pack.mcmeta' ) ,
172- )
173- const hasAssetsDir = Object . keys ( jszip . files ) . some (
174- ( f ) => f . toLowerCase ( ) === 'assets/' || f . toLowerCase ( ) . startsWith ( 'assets/' ) ,
175- )
176-
177- if ( hasMcmeta && hasAssetsDir ) {
178- projectType . value = 'resourcepack'
179- return projectType . value
180- }
181- }
182- } catch {
183- // not a zip
166+ if ( loaders . some ( ( loader ) => PROJECT_TYPE_LOADERS . datapack . includes ( loader ) ) ) {
167+ return 'datapack'
168+ }
169+ if ( loaders . some ( ( loader ) => PROJECT_TYPE_LOADERS . resourcepack . includes ( loader ) ) ) {
170+ return 'resourcepack'
171+ }
172+ if ( loaders . some ( ( loader ) => PROJECT_TYPE_LOADERS . shader . includes ( loader ) ) ) {
173+ return 'shader'
174+ }
175+ if ( loaders . some ( ( loader ) => PROJECT_TYPE_LOADERS . plugin . includes ( loader ) ) ) {
176+ return 'plugin'
177+ }
178+ if ( loaders . some ( ( loader ) => PROJECT_TYPE_LOADERS . mod . includes ( loader ) ) ) {
179+ return 'mod'
184180 }
185181
186- projectType . value = undefined
187- return undefined
188- }
182+ return 'project'
183+ } )
184+
185+ // Computed state
186+ const editingVersion = computed ( ( ) => Boolean ( draftVersion . value . version_id ) )
189187
190188 // Version management methods
191189 function newDraftVersion (
@@ -197,7 +195,7 @@ export function createManageVersionContext(
197195 filesToAdd . value = [ ]
198196 existingFilesToDelete . value = [ ]
199197 inferredVersionData . value = undefined
200- projectType . value = undefined
198+ // projectType.value = undefined
201199 }
202200
203201 function setPrimaryFile ( index : number ) {
@@ -210,6 +208,33 @@ export function createManageVersionContext(
210208
211209 const tags = useGeneratedState ( )
212210
211+ const hasFile = ( entries : string [ ] , name : string ) =>
212+ entries . some ( ( f ) => f === name || f . endsWith ( `/${ name } ` ) )
213+
214+ const hasDir = ( entries : string [ ] , dir : string ) => entries . some ( ( f ) => f . startsWith ( `${ dir } /` ) )
215+
216+ async function checkIsResourcePack ( file : File ) : Promise < boolean > {
217+ try {
218+ const zip = await JSZip . loadAsync ( file )
219+ const entries = Object . keys ( zip . files ) . map ( ( f ) => f . toLowerCase ( ) )
220+
221+ return hasFile ( entries , 'pack.mcmeta' ) && hasDir ( entries , 'assets' )
222+ } catch {
223+ return false
224+ }
225+ }
226+
227+ async function checkIsDataPack ( file : File ) : Promise < boolean > {
228+ try {
229+ const zip = await JSZip . loadAsync ( file )
230+ const entries = Object . keys ( zip . files ) . map ( ( f ) => f . toLowerCase ( ) )
231+
232+ return hasFile ( entries , 'pack.mcmeta' ) && hasDir ( entries , 'data' )
233+ } catch {
234+ return false
235+ }
236+ }
237+
213238 async function setInferredVersionData (
214239 file : File ,
215240 project : Labrinth . Projects . v2 . Project ,
@@ -234,8 +259,21 @@ export function createManageVersionContext(
234259 console . error ( 'Error fetching versions for environment inference:' , error )
235260 }
236261
262+ const noLoaders = ! inferred . loaders ?. length
263+
264+ if ( noLoaders && ( await checkIsResourcePack ( file ) ) ) {
265+ inferred . loaders = [ 'minecraft' ]
266+ }
267+
268+ if ( noLoaders && ( await checkIsDataPack ( file ) ) ) {
269+ inferred . loaders = [ 'datapack' ]
270+ }
271+
272+ if ( noLoaders && projectType . value === 'modpack' ) {
273+ inferred . loaders = [ 'minecraft' ]
274+ }
275+
237276 inferredVersionData . value = inferred
238- projectType . value = await setProjectType ( project , file )
239277
240278 return inferred
241279 }
@@ -423,7 +461,6 @@ export function createManageVersionContext(
423461 newDraftVersion,
424462 setPrimaryFile,
425463 setInferredVersionData,
426- setProjectType,
427464 getProject,
428465 getVersion,
429466 handleCreateVersion,
0 commit comments