This repository was archived by the owner on May 2, 2026. It is now read-only.
Description 不知道作者的 mods_data.json 是怎么获取的
不过看着好累的样子
不知道您有没有看过这样一个思路:
检查jar包里的配置文件
希望能帮到您
如果您愿意的话,可以拿这个方案做原方案的兜底
我之前简单实现了以下
以下代码由AI生成
const fs = require ( 'fs/promises' ) ;
const path = require ( 'path' ) ;
const AdmZip = require ( 'adm-zip' ) ;
const toml = require ( '@iarna/toml' ) ;
const readline = require ( 'readline' ) ;
// ===================== 配置 =====================
const MODS_DIR = path . resolve ( './mods' ) ;
const BACKUP_DIR = path . resolve ( './backup_deleted_mods' ) ;
// =================================================
const rl = readline . createInterface ( {
input : process . stdin ,
output : process . stdout
} ) ;
function confirm ( msg ) {
return new Promise ( resolve => {
rl . question ( msg , ans => {
resolve ( ans . trim ( ) . toLowerCase ( ) === 'y' ) ;
} ) ;
} ) ;
}
// 正确判断:是否真·客户端MOD
async function isClientOnlyMod ( jarPath ) {
try {
const zip = new AdmZip ( jarPath ) ;
const neoforgeToml = zip . getEntry ( 'META-INF/neoforge.mods.toml' ) ;
const forgeToml = zip . getEntry ( 'META-INF/mods.toml' ) ;
const tomlEntry = neoforgeToml || forgeToml ;
if ( tomlEntry ) {
const content = tomlEntry . getData ( ) . toString ( 'utf8' ) ;
const parsed = toml . parse ( content ) ;
// 1. 看mod自身side
if ( Array . isArray ( parsed . mods ) ) {
for ( const mod of parsed . mods ) {
if ( mod . side === 'CLIENT' ) {
return true ;
}
}
}
// 2. 看依赖:必须是 required 且 side=CLIENT 才判定
if ( parsed . dependencies ) {
for ( const depKey of Object . keys ( parsed . dependencies ) ) {
const deps = parsed . dependencies [ depKey ] ;
if ( ! Array . isArray ( deps ) ) continue ;
for ( const d of deps ) {
if ( d . type === 'required' && d . side === 'CLIENT' ) {
return true ;
}
}
}
}
}
// Fabric / Quilt
const fabricEntry = zip . getEntry ( 'fabric.mod.json' ) ;
const quiltEntry = zip . getEntry ( 'quilt.mod.json' ) ;
const jsonEntry = fabricEntry || quiltEntry ;
if ( jsonEntry ) {
const json = JSON . parse ( jsonEntry . getData ( ) . toString ( 'utf8' ) ) ;
if ( json . environment === 'client' ) {
return true ;
}
}
return false ;
} catch ( e ) {
console . log ( `[⚠️ 解析失败] ${ path . basename ( jarPath ) } ` ) ;
return false ;
}
}
async function ensureBackupDir ( ) {
try {
await fs . access ( BACKUP_DIR ) ;
} catch ( e ) {
await fs . mkdir ( BACKUP_DIR , { recursive : true } ) ;
}
}
async function backupFile ( filePath ) {
const fileName = path . basename ( filePath ) ;
const dest = path . join ( BACKUP_DIR , fileName ) ;
await fs . copyFile ( filePath , dest ) ;
}
async function scanAndClean ( ) {
console . log ( '📁 扫描 MOD 目录:' , MODS_DIR ) ;
console . log ( '🔍 识别 服务端无效 MOD(仅客户端)...\n' ) ;
let files ;
try {
files = await fs . readdir ( MODS_DIR ) ;
} catch ( e ) {
console . log ( '❌ mods 目录不存在!' ) ;
rl . close ( ) ;
return ;
}
const jarFiles = files
. filter ( f => f . toLowerCase ( ) . endsWith ( '.jar' ) )
. map ( f => path . join ( MODS_DIR , f ) ) ;
const clientOnlyList = [ ] ;
for ( const jar of jarFiles ) {
const name = path . basename ( jar ) ;
const clientOnly = await isClientOnlyMod ( jar ) ;
console . log ( `${ clientOnly ? '❌ 客户端' : '✅ 可服务端' } | ${ name } ` ) ;
if ( clientOnly ) clientOnlyList . push ( jar ) ;
}
if ( clientOnlyList . length === 0 ) {
console . log ( '\n🎉 没有需要删除的服务端无效 MOD' ) ;
rl . close ( ) ;
return ;
}
console . log ( `\n⚠️ 共找到 ${ clientOnlyList . length } 个服务端无效 MOD:` ) ;
clientOnlyList . forEach ( jar => console . log ( ' -' , path . basename ( jar ) ) ) ;
const yes = await confirm ( '\n🗑️ 确定删除并备份吗?(y/N) ' ) ;
if ( ! yes ) {
console . log ( '🚫 已取消' ) ;
rl . close ( ) ;
return ;
}
await ensureBackupDir ( ) ;
for ( const jar of clientOnlyList ) {
await backupFile ( jar ) ;
await fs . unlink ( jar ) ;
console . log ( '✅ 已删除并备份:' , path . basename ( jar ) ) ;
}
console . log ( '\n🎉 清理完成!已备份到 backup_deleted_mods' ) ;
rl . close ( ) ;
}
scanAndClean ( ) . catch ( err => {
console . error ( '💥 错误:' , err ) ;
rl . close ( ) ;
} ) ; Reactions are currently unavailable
不知道作者的
mods_data.json是怎么获取的不过看着好累的样子
不知道您有没有看过这样一个思路:
检查jar包里的配置文件
希望能帮到您
如果您愿意的话,可以拿这个方案做原方案的兜底
我之前简单实现了以下
以下代码由AI生成