diff --git a/lib/single-mod-checker.js b/lib/single-mod-checker.js index 81aef56c..5952ac0b 100644 --- a/lib/single-mod-checker.js +++ b/lib/single-mod-checker.js @@ -18,9 +18,18 @@ const PNG = require('pngjs').PNG class modFileChecker { #validFileTypes = [ - '.ogg', '.dds', '.i3d', '.shapes', '.lua', '.xml', '.grle', '.gls', '/' + '.png', '.anim', '.ogg', '.dds', '.i3d', '.shapes', '.lua', + '.gdm', '.cache', '.xml', '.grle', '.gls', '/' ] + #fileSizeMap = { + dds : [( 12 * 1024 * 1024 ), 'dds_too_big'], + xml : [( 0.25 * 1024 * 1024 ), 'xml_too_big'], + shapes : [( 256 * 1024 * 1024 ), 'shapes_too_big'], + cache : [( 10 * 1024 * 1024 ), 'i3d_too_big'], + gdm : [( 18 * 1024 * 1024 ), 'gdm_too_big'], + } + #failFlags = { first_digit : false, probable_copy : false, @@ -37,6 +46,17 @@ class modFileChecker { no_modIcon : false, folder_needs_zip : false, might_be_crack : false, + has_extra_files : false, + png_texture : false, + dds_too_big : false, // 12MB + xml_too_big : false, // 0.25MB + i3d_too_big : false, // 10MB + shapes_too_big : false, // 256MB + gdm_too_big : false, // 18MB + grle_too_many : false, // 10 + png_too_many : false, // 128 + space_in_file : false, // (internal files) + l10n_not_set : false, // set on processL10n if either null } #failMessages = { first_digit : 'FILE_ERROR_NAME_STARTS_DIGIT', @@ -54,6 +74,17 @@ class modFileChecker { no_modIcon : 'MOD_ERROR_NO_MOD_ICON', folder_needs_zip : 'INFO_NO_MULTIPLAYER_UNZIPPED', might_be_crack : 'INFO_MIGHT_BE_PIRACY', + has_extra_files : 'PERF_HAS_EXTRA', + png_texture : 'PREF_PNG_TEXTURE', + dds_too_big : 'PERF_DDS_TOO_BIG', // 12MB + xml_too_big : 'PERF_XML_TOO_BIG', // 0.25MB + i3d_too_big : 'PERF_I3D_TOO_BIG', // 10MB + shapes_too_big : 'PERF_SHAPES_TOO_BIG', // 256MB + gdm_too_big : 'PERF_GDM_TOO_BIG', // 18MB + grle_too_many : 'PERF_GRLE_TOO_MANY', // 10 + png_too_many : 'PERF_PNG_TOO_MANY', // 128 + space_in_file : 'PERF_SPACE_IN_FILE', // (internal files) + l10n_not_set : 'PERF_L10N_NOT_SET', // set on processL10n if either null } #flags_broken = [ @@ -64,7 +95,10 @@ class modFileChecker { ] #flags_problem = [ - 'might_be_crack', 'bad_modDesc' + 'might_be_crack', 'bad_modDesc', 'dds_too_big', 'xml_too_big', + 'i3d_too_big', 'shapes_too_big', 'gdm_too_big', 'grle_too_many', + 'png_too_many', 'space_in_file', 'l10n_not_set', 'has_extra_files', + 'png_texture' ] modDesc = { @@ -101,6 +135,9 @@ class modFileChecker { imageDDS : [], i3dFiles : [], extraFiles : [], + tooBigFiles : [], + spaceFiles : [], + pngTexture : [], } badges = '' @@ -149,6 +186,10 @@ class modFileChecker { populateL10n() { this.l10n.title = this.#getLocalString('title') this.l10n.description = this.#getLocalString('description') + + if ( this.l10n.title === null || this.l10n.description === null ) { + this.#failFlags.l10n_not_set = true + } } #populateIssues() { @@ -368,11 +409,33 @@ class modFileChecker { return } + const fileMax = { grle : 10, png : 128 } + zipEntries.forEach((entry) => { let isExtraFile = true + Object.keys(this.#fileSizeMap).forEach((fileType) => { + if ( entry.entryName.endsWith(`.${fileType}`) ) { + if ( entry.header.size > this.#fileSizeMap[fileType][0] ) { + this.#failFlags[this.#fileSizeMap[fileType][1]] = true + this.fileDetail.tooBigFiles.push(entry.entryName) + } + } + }) + if ( entry.entryName.includes(' ') ) { + this.fileDetail.spaceFiles.push(entry.entryName) + this.#failFlags.space_in_file = true + } + if ( entry.entryName.endsWith('.grle') ) { + fileMax.grle-- + } if ( entry.entryName.endsWith('.png') ) { this.fileDetail.imageNonDDS.push(entry.entryName) + if ( entry.entryName.includes('texture') ) { + this.fileDetail.pngTexture.push(entry.entryName) + this.#failFlags.png_texture = true + } + fileMax.png-- } if ( entry.entryName.endsWith('.dds') ) { this.fileDetail.imageDDS.push(entry.entryName) @@ -391,10 +454,14 @@ class modFileChecker { if ( isExtraFile && entry.entryName.endsWith(suffix) ) { isExtraFile = false } } if ( isExtraFile ) { + this.#failFlags.has_extra_files = true this.fileDetail.extraFiles.push(entry.entryName) } }) + if ( fileMax.grle < 1 ) { this.#failFlags.grle_too_many = true } + if ( fileMax.png < 1 ) { this.#failFlags.png_too_many = true } + try { this.modDesc.xmlDoc = zipFile.readAsText('modDesc.xml') } catch (e) { @@ -427,21 +494,54 @@ class modFileChecker { const allFileList = glob.sync('**', { cwd : this.fileDetail.fullPath, mark : true }) + const fileMax = { grle : 10, png : 128 } + for ( const checkFile of allFileList ) { + const fileStats = fs.statSync(path.join(this.fileDetail.fullPath, checkFile)) let extraFile = true + + Object.keys(this.#fileSizeMap).forEach((fileType) => { + if ( checkFile.endsWith(`.${fileType}`) ) { + if ( fileStats.size > this.#fileSizeMap[fileType][0] ) { + this.#failFlags[this.#fileSizeMap[fileType][1]] = true + this.fileDetail.tooBigFiles.push(checkFile) + } + } + }) + for ( const suffix of this.#validFileTypes ) { - if ( extraFile && checkFile.endsWith(suffix) ) { extraFile = false } + if ( extraFile && checkFile.endsWith(suffix) ) { + extraFile = false + } + } + + if ( checkFile.includes(' ') ) { + this.fileDetail.spaceFiles.push(checkFile) + this.#failFlags.space_in_file = true } - if ( extraFile ) { this.fileDetail.extraFiles.push(checkFile) } + + if ( extraFile ) { this.#failFlags.has_extra_files = true; this.fileDetail.extraFiles.push(checkFile) } if ( checkFile.endsWith('.i3d') ) { this.fileDetail.i3dFiles.push(checkFile) } if ( checkFile.endsWith('.dds') ) { this.fileDetail.imageDDS.push(checkFile) } - if ( checkFile.endsWith('.png') ) { this.fileDetail.imageNonDDS.push(checkFile) } + if ( checkFile.endsWith('.png') ) { + fileMax.png-- + this.fileDetail.imageNonDDS.push(checkFile) + if ( checkFile.includes('texture') ) { + this.fileDetail.pngTexture.push(checkFile) + this.#failFlags.png_texture = true + } + } + if ( checkFile.endsWith('.grle') ) { fileMax.grle-- } if ( checkFile.endsWith('.lua') ) { this.modDesc.scriptFiles++ } if ( checkFile.endsWith('.l64') ) { this.#failFlags.might_be_crack = true } if ( checkFile.endsWith('productID.dat') ) { this.#failFlags.might_be_crack = true } } + if ( fileMax.grle < 1 ) { this.#failFlags.grle_too_many = true } + if ( fileMax.png < 1 ) { this.#failFlags.png_too_many = true } + + if ( ! this.#failFlags.no_modDesc ) { this.#processModDesc() } diff --git a/modAssist_main.js b/modAssist_main.js index e9af1c86..20fb8d64 100644 --- a/modAssist_main.js +++ b/modAssist_main.js @@ -11,7 +11,7 @@ const { app, BrowserWindow, ipcMain, globalShortcut, shell, dialog, screen } = r const { autoUpdater } = require('electron-updater') -const devDebug = false +const devDebug = true if (process.platform === 'win32') { autoUpdater.checkForUpdatesAndNotify() @@ -251,6 +251,7 @@ function createDetailWindow(thisModRecord) { windows.detail.webContents.on('did-finish-load', async (event) => { event.sender.send('fromMain_modRecord', thisModRecord) + if ( devDebug ) { windows.detail.webContents.openDevTools() } }) windows.detail.loadFile(path.join(pathRender, 'detail.html')) diff --git a/package.json b/package.json index 4168ad03..403c58c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fsg-mod-assistant", - "version": "0.9.2", + "version": "0.9.3", "description": "FSG Farm Sim Mod Assistant", "main": "modAssist_main.js", "homepage": "https://github.com/FSGModding/FSG_Mod_Assistant#readme", diff --git a/renderer/detail.html b/renderer/detail.html index 3ef35f7f..982e7ee3 100644 --- a/renderer/detail.html +++ b/renderer/detail.html @@ -43,14 +43,23 @@

-
+
-
-
+
+

+
+
+

-
+
-
+
+
+
+
+
+
+
diff --git a/renderer/renderJS/detail_ui.js b/renderer/renderJS/detail_ui.js index fab8f329..fde26591 100644 --- a/renderer/renderJS/detail_ui.js +++ b/renderer/renderJS/detail_ui.js @@ -46,6 +46,9 @@ window.mods.receive('fromMain_modRecord', (modRecord) => { description : modRecord.l10n.description, i3dFiles : modRecord.fileDetail.i3dFiles.join('\n'), extraFiles : (( modRecord.fileDetail.extraFiles.length > 0 ) ? modRecord.fileDetail.extraFiles.join('\n') : ''), + bigFiles : (( modRecord.fileDetail.tooBigFiles.length > 0 ) ? modRecord.fileDetail.tooBigFiles.join('\n') : ''), + spaceFiles : (( modRecord.fileDetail.spaceFiles.length > 0 ) ? modRecord.fileDetail.spaceFiles.join('\n') : ''), + pngTexture : (( modRecord.fileDetail.pngTexture.length > 0 ) ? modRecord.fileDetail.pngTexture.join('\n') : ''), } Object.keys(idMap).forEach((key) => { fsgUtil.byId(key).innerHTML = idMap[key] @@ -63,7 +66,7 @@ window.mods.receive('fromMain_modRecord', (modRecord) => { } problems.push(`${checkX(0, false)}${issueText}`) }) - fsgUtil.byId('problems').innerHTML = `${problems.join('')}
` + fsgUtil.byId('problems').innerHTML = `${problems.join('')}
` } textOrHide( diff --git a/translations/en.json b/translations/en.json index 7138c414..a784f698 100644 --- a/translations/en.json +++ b/translations/en.json @@ -56,6 +56,7 @@ "open_debug_log" : "View Debug Log", "detail_problems" : "Issues with this Mod", + "detail_description" : "Description", "detail_mod_version" : "Version", "detail_mod_size" : "Size", "detail_mod_date" : "Date", @@ -68,7 +69,10 @@ "detail_dev_info" : "Developer Information", "detail_extra_files" : "Extra files in the mod (per Giants spec)", "detail_i3d_files" : "i3D files in the mod", + "detail_space_files" : "Files with space in filename", + "detail_big_files" : "Oversized files", "detail_extra_clean" : "None, archive is clean", + "detail_png_textures" : "Possible PNG Texture files", "file_error_name_starts_digit" : "This file starts with a digit. FS requires that mods start with a letter.", "file_error_likely_copy" : "This file name suggests that it is a duplicate copy of another mod.", @@ -91,6 +95,18 @@ "file_error_copy_identical" : "The original file and this file are identical.", "info_might_be_piracy" : "This mod appears to be a cracked / pirated version of a paid DLC. This test is simplistic, so this could be a false positive, however be aware that using cracked DLC will prevent you from receiving help from Giants support, and is grounds for a ban from the official discord and forums. Please support the developers!", "info_might_be_duplicate" : "Based on their title, these mods might be duplicates of each other. You should compare versions and see if some could be removed.", + "perf_has_extra" : "Performance Consideration - Mod has unnecessary files", + "perf_dds_too_big" : "Performance Consideration - One or more DDS files is too big (12MB)", + "perf_xml_too_big" : "Performance Consideration - One or more XML files is too big (0.25MB)", + "perf_i3d_too_big" : "Performance Consideration - One or more I3D...CACHE files is too big (10MB)", + "perf_shapes_too_big" : "Performance Consideration - One or more SHAPES files is too big (256MB)", + "perf_gdm_too_big" : "Performance Consideration - One or more GDM files is too big (18MB)", + "perf_grle_too_many" : "Performance Consideration - Too many GRLEs in mod (10+)", + "perf_png_too_many" : "Performance Consideration - Too many PNGs in mod (128+)", + "perf_space_in_file" : "Performance Consideration - File(s) contain spaces", + "perf_l10n_not_set" : "Performance Consideration - L10N Entries in ModDesc are not set", + "png_texture" : "Performance Consideration - PNG files should not be used as textures", + "user_pref_title_main" : "User Preferences", "user_pref_title_lang" : "Language",