Skip to content

Commit 66cca9e

Browse files
jebibotdscalzi
authored andcommitted
feat: support Fabric (dscalzi#313)
* feat: support Fabric * fix: GAME_LAUNCH_REGEX for Fabric * Small refactor. * Update documentation. * Upgrade helios-distribution-types, helios-core. --------- Co-authored-by: Daniel Scalzi <[email protected]>
1 parent 4b04e88 commit 66cca9e

File tree

7 files changed

+105
-85
lines changed

7 files changed

+105
-85
lines changed

app/assets/js/processbuilder.js

+47-63
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,23 @@ const ConfigManager = require('./configmanager')
1212

1313
const logger = LoggerUtil.getLogger('ProcessBuilder')
1414

15+
16+
/**
17+
* Only forge and fabric are top level mod loaders.
18+
*
19+
* Forge 1.13+ launch logic is similar to fabrics, for now using usingFabricLoader flag to
20+
* change minor details when needed.
21+
*
22+
* Rewrite of this module may be needed in the future.
23+
*/
1524
class ProcessBuilder {
1625

17-
constructor(distroServer, versionData, forgeData, authUser, launcherVersion){
26+
constructor(distroServer, vanillaManifest, modManifest, authUser, launcherVersion){
1827
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.rawServer.id)
1928
this.commonDir = ConfigManager.getCommonDirectory()
2029
this.server = distroServer
21-
this.versionData = versionData
22-
this.forgeData = forgeData
30+
this.vanillaManifest = vanillaManifest
31+
this.modManifest = modManifest
2332
this.authUser = authUser
2433
this.launcherVersion = launcherVersion
2534
this.forgeModListFile = path.join(this.gameDir, 'forgeMods.list') // 1.13+
@@ -28,6 +37,7 @@ class ProcessBuilder {
2837
this.libPath = path.join(this.commonDir, 'libraries')
2938

3039
this.usingLiteLoader = false
40+
this.usingFabricLoader = false
3141
this.llPath = null
3242
}
3343

@@ -40,9 +50,12 @@ class ProcessBuilder {
4050
process.throwDeprecation = true
4151
this.setupLiteLoader()
4252
logger.info('Using liteloader:', this.usingLiteLoader)
53+
this.usingFabricLoader = this.server.modules.some(mdl => mdl.rawModule.type === Type.Fabric)
54+
logger.info('Using fabric loader:', this.usingFabricLoader)
4355
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules)
4456

4557
// Mod list below 1.13
58+
// Fabric only supports 1.14+
4659
if(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
4760
this.constructJSONModList('forge', modObj.fMods, true)
4861
if(this.usingLiteLoader){
@@ -166,7 +179,7 @@ class ProcessBuilder {
166179

167180
for(let mdl of mdls){
168181
const type = mdl.rawModule.type
169-
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
182+
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
170183
const o = !mdl.getRequired().value
171184
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
172185
if(!o || (o && e)){
@@ -178,7 +191,7 @@ class ProcessBuilder {
178191
continue
179192
}
180193
}
181-
if(type === Type.ForgeMod){
194+
if(type === Type.ForgeMod || type === Type.FabricMod){
182195
fMods.push(mdl)
183196
} else {
184197
lMods.push(mdl)
@@ -194,7 +207,7 @@ class ProcessBuilder {
194207
}
195208

196209
_lteMinorVersion(version) {
197-
return Number(this.forgeData.id.split('-')[0].split('.')[1]) <= Number(version)
210+
return Number(this.modManifest.id.split('-')[0].split('.')[1]) <= Number(version)
198211
}
199212

200213
/**
@@ -206,7 +219,7 @@ class ProcessBuilder {
206219
if(this._lteMinorVersion(9)) {
207220
return false
208221
}
209-
const ver = this.forgeData.id.split('-')[2]
222+
const ver = this.modManifest.id.split('-')[2]
210223
const pts = ver.split('.')
211224
const min = [14, 23, 3, 2655]
212225
for(let i=0; i<pts.length; i++){
@@ -282,18 +295,21 @@ class ProcessBuilder {
282295
// }
283296

284297
/**
285-
* Construct the mod argument list for forge 1.13
298+
* Construct the mod argument list for forge 1.13 and Fabric
286299
*
287300
* @param {Array.<Object>} mods An array of mods to add to the mod list.
288301
*/
289302
constructModList(mods) {
290303
const writeBuffer = mods.map(mod => {
291-
return mod.getExtensionlessMavenIdentifier()
304+
return this.usingFabricLoader ? mod.getPath() : mod.getExtensionlessMavenIdentifier()
292305
}).join('\n')
293306

294307
if(writeBuffer) {
295308
fs.writeFileSync(this.forgeModListFile, writeBuffer, 'UTF-8')
296-
return [
309+
return this.usingFabricLoader ? [
310+
'--fabric.addMods',
311+
`@${this.forgeModListFile}`
312+
] : [
297313
'--fml.mavenRoots',
298314
path.join('..', '..', 'common', 'modstore'),
299315
'--fml.modLists',
@@ -361,7 +377,7 @@ class ProcessBuilder {
361377
args.push('-Djava.library.path=' + tempNativePath)
362378

363379
// Main Java Class
364-
args.push(this.forgeData.mainClass)
380+
args.push(this.modManifest.mainClass)
365381

366382
// Forge Arguments
367383
args = args.concat(this._resolveForgeArgs())
@@ -384,17 +400,17 @@ class ProcessBuilder {
384400
const argDiscovery = /\${*(.*)}/
385401

386402
// JVM Arguments First
387-
let args = this.versionData.arguments.jvm
403+
let args = this.vanillaManifest.arguments.jvm
388404

389405
// Debug securejarhandler
390406
// args.push('-Dbsl.debug=true')
391407

392-
if(this.forgeData.arguments.jvm != null) {
393-
for(const argStr of this.forgeData.arguments.jvm) {
408+
if(this.modManifest.arguments.jvm != null) {
409+
for(const argStr of this.modManifest.arguments.jvm) {
394410
args.push(argStr
395411
.replaceAll('${library_directory}', this.libPath)
396412
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
397-
.replaceAll('${version_name}', this.forgeData.id)
413+
.replaceAll('${version_name}', this.modManifest.id)
398414
)
399415
}
400416
}
@@ -411,10 +427,10 @@ class ProcessBuilder {
411427
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
412428

413429
// Main Java Class
414-
args.push(this.forgeData.mainClass)
430+
args.push(this.modManifest.mainClass)
415431

416432
// Vanilla Arguments
417-
args = args.concat(this.versionData.arguments.game)
433+
args = args.concat(this.vanillaManifest.arguments.game)
418434

419435
for(let i=0; i<args.length; i++){
420436
if(typeof args[i] === 'object' && args[i].rules != null){
@@ -471,7 +487,7 @@ class ProcessBuilder {
471487
val = this.authUser.displayName.trim()
472488
break
473489
case 'version_name':
474-
//val = versionData.id
490+
//val = vanillaManifest.id
475491
val = this.server.rawServer.id
476492
break
477493
case 'game_directory':
@@ -481,7 +497,7 @@ class ProcessBuilder {
481497
val = path.join(this.commonDir, 'assets')
482498
break
483499
case 'assets_index_name':
484-
val = this.versionData.assets
500+
val = this.vanillaManifest.assets
485501
break
486502
case 'auth_uuid':
487503
val = this.authUser.uuid.trim()
@@ -493,7 +509,7 @@ class ProcessBuilder {
493509
val = this.authUser.type === 'microsoft' ? 'msa' : 'mojang'
494510
break
495511
case 'version_type':
496-
val = this.versionData.type
512+
val = this.vanillaManifest.type
497513
break
498514
case 'resolution_width':
499515
val = ConfigManager.getGameWidth()
@@ -522,25 +538,11 @@ class ProcessBuilder {
522538
}
523539

524540
// Autoconnect
525-
let isAutoconnectBroken
526-
try {
527-
isAutoconnectBroken = ProcessBuilder.isAutoconnectBroken(this.forgeData.id.split('-')[2])
528-
} catch(err) {
529-
logger.error(err)
530-
logger.error('Forge version format changed.. assuming autoconnect works.')
531-
logger.debug('Forge version:', this.forgeData.id)
532-
}
533-
534-
if(isAutoconnectBroken) {
535-
logger.error('Server autoconnect disabled on Forge 1.15.2 for builds earlier than 31.2.15 due to OpenGL Stack Overflow issue.')
536-
logger.error('Please upgrade your Forge version to at least 31.2.15!')
537-
} else {
538-
this._processAutoConnectArg(args)
539-
}
541+
this._processAutoConnectArg(args)
540542

541543

542544
// Forge Specific Arguments
543-
args = args.concat(this.forgeData.arguments.game)
545+
args = args.concat(this.modManifest.arguments.game)
544546

545547
// Filter null values
546548
args = args.filter(arg => {
@@ -556,7 +558,7 @@ class ProcessBuilder {
556558
* @returns {Array.<string>} An array containing the arguments required by forge.
557559
*/
558560
_resolveForgeArgs(){
559-
const mcArgs = this.forgeData.minecraftArguments.split(' ')
561+
const mcArgs = this.modManifest.minecraftArguments.split(' ')
560562
const argDiscovery = /\${*(.*)}/
561563

562564
// Replace the declared variables with their proper values.
@@ -569,7 +571,7 @@ class ProcessBuilder {
569571
val = this.authUser.displayName.trim()
570572
break
571573
case 'version_name':
572-
//val = versionData.id
574+
//val = vanillaManifest.id
573575
val = this.server.rawServer.id
574576
break
575577
case 'game_directory':
@@ -579,7 +581,7 @@ class ProcessBuilder {
579581
val = path.join(this.commonDir, 'assets')
580582
break
581583
case 'assets_index_name':
582-
val = this.versionData.assets
584+
val = this.vanillaManifest.assets
583585
break
584586
case 'auth_uuid':
585587
val = this.authUser.uuid.trim()
@@ -594,7 +596,7 @@ class ProcessBuilder {
594596
val = '{}'
595597
break
596598
case 'version_type':
597-
val = this.versionData.type
599+
val = this.vanillaManifest.type
598600
break
599601
}
600602
if(val != null){
@@ -669,10 +671,10 @@ class ProcessBuilder {
669671
classpathArg(mods, tempNativePath){
670672
let cpArgs = []
671673

672-
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion)) {
674+
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion) || this.usingFabricLoader) {
673675
// Add the version.jar to the classpath.
674676
// Must not be added to the classpath for Forge 1.17+.
675-
const version = this.versionData.id
677+
const version = this.vanillaManifest.id
676678
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
677679
}
678680

@@ -711,7 +713,7 @@ class ProcessBuilder {
711713
const nativesRegex = /.+:natives-([^-]+)(?:-(.+))?/
712714
const libs = {}
713715

714-
const libArr = this.versionData.libraries
716+
const libArr = this.vanillaManifest.libraries
715717
fs.ensureDirSync(tempNativePath)
716718
for(let i=0; i<libArr.length; i++){
717719
const lib = libArr[i]
@@ -830,10 +832,10 @@ class ProcessBuilder {
830832
const mdls = this.server.modules
831833
let libs = {}
832834

833-
// Locate Forge/Libraries
835+
// Locate Forge/Fabric/Libraries
834836
for(let mdl of mdls){
835837
const type = mdl.rawModule.type
836-
if(type === Type.ForgeHosted || type === Type.Library){
838+
if(type === Type.ForgeHosted || type === Type.Fabric || type === Type.Library){
837839
libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
838840
if(mdl.subModules.length > 0){
839841
const res = this._resolveModuleLibraries(mdl)
@@ -887,24 +889,6 @@ class ProcessBuilder {
887889
return libs
888890
}
889891

890-
static isAutoconnectBroken(forgeVersion) {
891-
892-
const minWorking = [31, 2, 15]
893-
const verSplit = forgeVersion.split('.').map(v => Number(v))
894-
895-
if(verSplit[0] === 31) {
896-
for(let i=0; i<minWorking.length; i++) {
897-
if(verSplit[i] > minWorking[i]) {
898-
return false
899-
} else if(verSplit[i] < minWorking[i]) {
900-
return true
901-
}
902-
}
903-
}
904-
905-
return false
906-
}
907-
908892
}
909893

910894
module.exports = ProcessBuilder

app/assets/js/scripts/landing.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ let hasRPC = false
442442
// Joined server regex
443443
// Change this if your server uses something different.
444444
const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
445-
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/
445+
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+|Loading Minecraft .+ with Fabric Loader .+)$/
446446
const MIN_LINGER = 5000
447447

448448
async function dlAsync(login = true) {
@@ -548,13 +548,13 @@ async function dlAsync(login = true) {
548548
serv.rawServer.id
549549
)
550550

551-
const forgeData = await distributionIndexProcessor.loadForgeVersionJson(serv)
551+
const modLoaderData = await distributionIndexProcessor.loadModLoaderVersionJson(serv)
552552
const versionData = await mojangIndexProcessor.getVersionJson()
553553

554554
if(login) {
555555
const authUser = ConfigManager.getSelectedAccount()
556556
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
557-
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion())
557+
let pb = new ProcessBuilder(serv, versionData, modLoaderData, authUser, remote.app.getVersion())
558558
setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame'))
559559

560560
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/

app/assets/js/scripts/settings.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ function parseModulesForUI(mdls, submodules, servConf){
736736

737737
for(const mdl of mdls){
738738

739-
if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader){
739+
if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader || mdl.rawModule.type === Type.FabricMod){
740740

741741
if(mdl.getRequired().value){
742742

app/assets/js/scripts/uibinder.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ function syncModConfigurations(data){
163163
for(let mdl of mdls){
164164
const type = mdl.rawModule.type
165165

166-
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
166+
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
167167
if(!mdl.getRequired().value){
168168
const mdlID = mdl.getVersionlessMavenIdentifier()
169169
if(modsOld[mdlID] == null){
@@ -198,7 +198,7 @@ function syncModConfigurations(data){
198198

199199
for(let mdl of mdls){
200200
const type = mdl.rawModule.type
201-
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
201+
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
202202
if(!mdl.getRequired().value){
203203
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
204204
} else {
@@ -253,7 +253,7 @@ function scanOptionalSubModules(mdls, origin){
253253
for(let mdl of mdls){
254254
const type = mdl.rawModule.type
255255
// Optional types.
256-
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
256+
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
257257
// It is optional.
258258
if(!mdl.getRequired().value){
259259
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)

0 commit comments

Comments
 (0)