Compare commits

...

4 Commits

Author SHA1 Message Date
jebibot
bf87d83203
Merge fe1f8d63f3 into 9b898cc033 2023-12-02 06:48:22 +00:00
Daniel Scalzi
fe1f8d63f3
Small refactor. 2023-12-02 01:48:06 -05:00
jebibot
3185146d60
fix: GAME_LAUNCH_REGEX for Fabric 2023-12-01 23:07:44 -05:00
jebibot
bc2dc371d0
feat: support Fabric 2023-12-01 23:07:38 -05:00
4 changed files with 54 additions and 70 deletions

View File

@ -12,14 +12,23 @@ const ConfigManager = require('./configmanager')
const logger = LoggerUtil.getLogger('ProcessBuilder') const logger = LoggerUtil.getLogger('ProcessBuilder')
/**
* Only forge and fabric are top level mod loaders.
*
* Forge 1.13+ launch logic is similar to fabrics, for now using usingFabricLoader flag to
* change minor details when needed.
*
* Rewrite of this module may be needed in the future.
*/
class ProcessBuilder { class ProcessBuilder {
constructor(distroServer, versionData, forgeData, authUser, launcherVersion){ constructor(distroServer, vanillaManifest, modManifest, authUser, launcherVersion){
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.rawServer.id) this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.rawServer.id)
this.commonDir = ConfigManager.getCommonDirectory() this.commonDir = ConfigManager.getCommonDirectory()
this.server = distroServer this.server = distroServer
this.versionData = versionData this.vanillaManifest = vanillaManifest
this.forgeData = forgeData this.modManifest = modManifest
this.authUser = authUser this.authUser = authUser
this.launcherVersion = launcherVersion this.launcherVersion = launcherVersion
this.forgeModListFile = path.join(this.gameDir, 'forgeMods.list') // 1.13+ this.forgeModListFile = path.join(this.gameDir, 'forgeMods.list') // 1.13+
@ -28,6 +37,7 @@ class ProcessBuilder {
this.libPath = path.join(this.commonDir, 'libraries') this.libPath = path.join(this.commonDir, 'libraries')
this.usingLiteLoader = false this.usingLiteLoader = false
this.usingFabricLoader = false
this.llPath = null this.llPath = null
} }
@ -40,9 +50,12 @@ class ProcessBuilder {
process.throwDeprecation = true process.throwDeprecation = true
this.setupLiteLoader() this.setupLiteLoader()
logger.info('Using liteloader:', this.usingLiteLoader) logger.info('Using liteloader:', this.usingLiteLoader)
this.usingFabricLoader = this.server.modules.some(mdl => mdl.rawModule.type === Type.Fabric)
logger.info('Using fabric loader:', this.usingFabricLoader)
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules) const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules)
// Mod list below 1.13 // Mod list below 1.13
// Fabric only supports 1.14+
if(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){ if(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
this.constructJSONModList('forge', modObj.fMods, true) this.constructJSONModList('forge', modObj.fMods, true)
if(this.usingLiteLoader){ if(this.usingLiteLoader){
@ -166,7 +179,7 @@ class ProcessBuilder {
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.rawModule.type const type = mdl.rawModule.type
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
const o = !mdl.getRequired().value const o = !mdl.getRequired().value
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired()) const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
if(!o || (o && e)){ if(!o || (o && e)){
@ -178,7 +191,7 @@ class ProcessBuilder {
continue continue
} }
} }
if(type === Type.ForgeMod){ if(type === Type.ForgeMod || type === Type.FabricMod){
fMods.push(mdl) fMods.push(mdl)
} else { } else {
lMods.push(mdl) lMods.push(mdl)
@ -194,7 +207,7 @@ class ProcessBuilder {
} }
_lteMinorVersion(version) { _lteMinorVersion(version) {
return Number(this.forgeData.id.split('-')[0].split('.')[1]) <= Number(version) return Number(this.modManifest.id.split('-')[0].split('.')[1]) <= Number(version)
} }
/** /**
@ -206,7 +219,7 @@ class ProcessBuilder {
if(this._lteMinorVersion(9)) { if(this._lteMinorVersion(9)) {
return false return false
} }
const ver = this.forgeData.id.split('-')[2] const ver = this.modManifest.id.split('-')[2]
const pts = ver.split('.') const pts = ver.split('.')
const min = [14, 23, 3, 2655] const min = [14, 23, 3, 2655]
for(let i=0; i<pts.length; i++){ for(let i=0; i<pts.length; i++){
@ -282,18 +295,21 @@ class ProcessBuilder {
// } // }
/** /**
* Construct the mod argument list for forge 1.13 * Construct the mod argument list for forge 1.13 and Fabric
* *
* @param {Array.<Object>} mods An array of mods to add to the mod list. * @param {Array.<Object>} mods An array of mods to add to the mod list.
*/ */
constructModList(mods) { constructModList(mods) {
const writeBuffer = mods.map(mod => { const writeBuffer = mods.map(mod => {
return mod.getExtensionlessMavenIdentifier() return this.usingFabricLoader ? mod.getPath() : mod.getExtensionlessMavenIdentifier()
}).join('\n') }).join('\n')
if(writeBuffer) { if(writeBuffer) {
fs.writeFileSync(this.forgeModListFile, writeBuffer, 'UTF-8') fs.writeFileSync(this.forgeModListFile, writeBuffer, 'UTF-8')
return [ return this.usingFabricLoader ? [
'--fabric.addMods',
`@${this.forgeModListFile}`
] : [
'--fml.mavenRoots', '--fml.mavenRoots',
path.join('..', '..', 'common', 'modstore'), path.join('..', '..', 'common', 'modstore'),
'--fml.modLists', '--fml.modLists',
@ -361,7 +377,7 @@ class ProcessBuilder {
args.push('-Djava.library.path=' + tempNativePath) args.push('-Djava.library.path=' + tempNativePath)
// Main Java Class // Main Java Class
args.push(this.forgeData.mainClass) args.push(this.modManifest.mainClass)
// Forge Arguments // Forge Arguments
args = args.concat(this._resolveForgeArgs()) args = args.concat(this._resolveForgeArgs())
@ -384,17 +400,17 @@ class ProcessBuilder {
const argDiscovery = /\${*(.*)}/ const argDiscovery = /\${*(.*)}/
// JVM Arguments First // JVM Arguments First
let args = this.versionData.arguments.jvm let args = this.vanillaManifest.arguments.jvm
// Debug securejarhandler // Debug securejarhandler
// args.push('-Dbsl.debug=true') // args.push('-Dbsl.debug=true')
if(this.forgeData.arguments.jvm != null) { if(this.modManifest.arguments.jvm != null) {
for(const argStr of this.forgeData.arguments.jvm) { for(const argStr of this.modManifest.arguments.jvm) {
args.push(argStr args.push(argStr
.replaceAll('${library_directory}', this.libPath) .replaceAll('${library_directory}', this.libPath)
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator()) .replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
.replaceAll('${version_name}', this.forgeData.id) .replaceAll('${version_name}', this.modManifest.id)
) )
} }
} }
@ -411,10 +427,10 @@ class ProcessBuilder {
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id)) args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
// Main Java Class // Main Java Class
args.push(this.forgeData.mainClass) args.push(this.modManifest.mainClass)
// Vanilla Arguments // Vanilla Arguments
args = args.concat(this.versionData.arguments.game) args = args.concat(this.vanillaManifest.arguments.game)
for(let i=0; i<args.length; i++){ for(let i=0; i<args.length; i++){
if(typeof args[i] === 'object' && args[i].rules != null){ if(typeof args[i] === 'object' && args[i].rules != null){
@ -471,7 +487,7 @@ class ProcessBuilder {
val = this.authUser.displayName.trim() val = this.authUser.displayName.trim()
break break
case 'version_name': case 'version_name':
//val = versionData.id //val = vanillaManifest.id
val = this.server.rawServer.id val = this.server.rawServer.id
break break
case 'game_directory': case 'game_directory':
@ -481,7 +497,7 @@ class ProcessBuilder {
val = path.join(this.commonDir, 'assets') val = path.join(this.commonDir, 'assets')
break break
case 'assets_index_name': case 'assets_index_name':
val = this.versionData.assets val = this.vanillaManifest.assets
break break
case 'auth_uuid': case 'auth_uuid':
val = this.authUser.uuid.trim() val = this.authUser.uuid.trim()
@ -493,7 +509,7 @@ class ProcessBuilder {
val = this.authUser.type === 'microsoft' ? 'msa' : 'mojang' val = this.authUser.type === 'microsoft' ? 'msa' : 'mojang'
break break
case 'version_type': case 'version_type':
val = this.versionData.type val = this.vanillaManifest.type
break break
case 'resolution_width': case 'resolution_width':
val = ConfigManager.getGameWidth() val = ConfigManager.getGameWidth()
@ -522,25 +538,11 @@ class ProcessBuilder {
} }
// Autoconnect // Autoconnect
let isAutoconnectBroken
try {
isAutoconnectBroken = ProcessBuilder.isAutoconnectBroken(this.forgeData.id.split('-')[2])
} catch(err) {
logger.error(err)
logger.error('Forge version format changed.. assuming autoconnect works.')
logger.debug('Forge version:', this.forgeData.id)
}
if(isAutoconnectBroken) {
logger.error('Server autoconnect disabled on Forge 1.15.2 for builds earlier than 31.2.15 due to OpenGL Stack Overflow issue.')
logger.error('Please upgrade your Forge version to at least 31.2.15!')
} else {
this._processAutoConnectArg(args) this._processAutoConnectArg(args)
}
// Forge Specific Arguments // Forge Specific Arguments
args = args.concat(this.forgeData.arguments.game) args = args.concat(this.modManifest.arguments.game)
// Filter null values // Filter null values
args = args.filter(arg => { args = args.filter(arg => {
@ -556,7 +558,7 @@ class ProcessBuilder {
* @returns {Array.<string>} An array containing the arguments required by forge. * @returns {Array.<string>} An array containing the arguments required by forge.
*/ */
_resolveForgeArgs(){ _resolveForgeArgs(){
const mcArgs = this.forgeData.minecraftArguments.split(' ') const mcArgs = this.modManifest.minecraftArguments.split(' ')
const argDiscovery = /\${*(.*)}/ const argDiscovery = /\${*(.*)}/
// Replace the declared variables with their proper values. // Replace the declared variables with their proper values.
@ -569,7 +571,7 @@ class ProcessBuilder {
val = this.authUser.displayName.trim() val = this.authUser.displayName.trim()
break break
case 'version_name': case 'version_name':
//val = versionData.id //val = vanillaManifest.id
val = this.server.rawServer.id val = this.server.rawServer.id
break break
case 'game_directory': case 'game_directory':
@ -579,7 +581,7 @@ class ProcessBuilder {
val = path.join(this.commonDir, 'assets') val = path.join(this.commonDir, 'assets')
break break
case 'assets_index_name': case 'assets_index_name':
val = this.versionData.assets val = this.vanillaManifest.assets
break break
case 'auth_uuid': case 'auth_uuid':
val = this.authUser.uuid.trim() val = this.authUser.uuid.trim()
@ -594,7 +596,7 @@ class ProcessBuilder {
val = '{}' val = '{}'
break break
case 'version_type': case 'version_type':
val = this.versionData.type val = this.vanillaManifest.type
break break
} }
if(val != null){ if(val != null){
@ -669,10 +671,10 @@ class ProcessBuilder {
classpathArg(mods, tempNativePath){ classpathArg(mods, tempNativePath){
let cpArgs = [] let cpArgs = []
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion)) { if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion) || this.usingFabricLoader) {
// Add the version.jar to the classpath. // Add the version.jar to the classpath.
// Must not be added to the classpath for Forge 1.17+. // Must not be added to the classpath for Forge 1.17+.
const version = this.versionData.id const version = this.vanillaManifest.id
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar')) cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
} }
@ -711,7 +713,7 @@ class ProcessBuilder {
const nativesRegex = /.+:natives-([^-]+)(?:-(.+))?/ const nativesRegex = /.+:natives-([^-]+)(?:-(.+))?/
const libs = {} const libs = {}
const libArr = this.versionData.libraries const libArr = this.vanillaManifest.libraries
fs.ensureDirSync(tempNativePath) fs.ensureDirSync(tempNativePath)
for(let i=0; i<libArr.length; i++){ for(let i=0; i<libArr.length; i++){
const lib = libArr[i] const lib = libArr[i]
@ -830,10 +832,10 @@ class ProcessBuilder {
const mdls = this.server.modules const mdls = this.server.modules
let libs = {} let libs = {}
// Locate Forge/Libraries // Locate Forge/Fabric/Libraries
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.rawModule.type const type = mdl.rawModule.type
if(type === Type.ForgeHosted || type === Type.Library){ if(type === Type.ForgeHosted || type === Type.Fabric || type === Type.Library){
libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath() libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
if(mdl.subModules.length > 0){ if(mdl.subModules.length > 0){
const res = this._resolveModuleLibraries(mdl) const res = this._resolveModuleLibraries(mdl)
@ -887,24 +889,6 @@ class ProcessBuilder {
return libs return libs
} }
static isAutoconnectBroken(forgeVersion) {
const minWorking = [31, 2, 15]
const verSplit = forgeVersion.split('.').map(v => Number(v))
if(verSplit[0] === 31) {
for(let i=0; i<minWorking.length; i++) {
if(verSplit[i] > minWorking[i]) {
return false
} else if(verSplit[i] < minWorking[i]) {
return true
}
}
}
return false
}
} }
module.exports = ProcessBuilder module.exports = ProcessBuilder

View File

@ -442,7 +442,7 @@ let hasRPC = false
// Joined server regex // Joined server regex
// Change this if your server uses something different. // Change this if your server uses something different.
const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/ const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/ const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+|Loading Minecraft .+ with Fabric Loader .+)$/
const MIN_LINGER = 5000 const MIN_LINGER = 5000
async function dlAsync(login = true) { async function dlAsync(login = true) {
@ -548,13 +548,13 @@ async function dlAsync(login = true) {
serv.rawServer.id serv.rawServer.id
) )
const forgeData = await distributionIndexProcessor.loadForgeVersionJson(serv) const modLoaderData = await distributionIndexProcessor.loadModLoaderVersionJson(serv)
const versionData = await mojangIndexProcessor.getVersionJson() const versionData = await mojangIndexProcessor.getVersionJson()
if(login) { if(login) {
const authUser = ConfigManager.getSelectedAccount() const authUser = ConfigManager.getSelectedAccount()
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`) loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion()) let pb = new ProcessBuilder(serv, versionData, modLoaderData, authUser, remote.app.getVersion())
setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame')) setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame'))
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/ // const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/

View File

@ -736,7 +736,7 @@ function parseModulesForUI(mdls, submodules, servConf){
for(const mdl of mdls){ for(const mdl of mdls){
if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader){ if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader || mdl.rawModule.type === Type.FabricMod){
if(mdl.getRequired().value){ if(mdl.getRequired().value){

View File

@ -163,7 +163,7 @@ function syncModConfigurations(data){
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.rawModule.type const type = mdl.rawModule.type
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
if(!mdl.getRequired().value){ if(!mdl.getRequired().value){
const mdlID = mdl.getVersionlessMavenIdentifier() const mdlID = mdl.getVersionlessMavenIdentifier()
if(modsOld[mdlID] == null){ if(modsOld[mdlID] == null){
@ -198,7 +198,7 @@ function syncModConfigurations(data){
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.rawModule.type const type = mdl.rawModule.type
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
if(!mdl.getRequired().value){ if(!mdl.getRequired().value){
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl) mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
} else { } else {
@ -253,7 +253,7 @@ function scanOptionalSubModules(mdls, origin){
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.rawModule.type const type = mdl.rawModule.type
// Optional types. // Optional types.
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
// It is optional. // It is optional.
if(!mdl.getRequired().value){ if(!mdl.getRequired().value){
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl) mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)