Skip to content

Commit

Permalink
Support split sources
Browse files Browse the repository at this point in the history
  • Loading branch information
modmuss50 committed Jun 11, 2024
1 parent 2cbe219 commit 8690ca5
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
64 changes: 62 additions & 2 deletions windows/Sources/FabricSandbox/SandboxCommandLine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,16 @@ class SandboxCommandLine {
args[0] = appPath.path()
}

var classpathMap: [String: String] = [:]

for i in 0..<args.count {
if args[i] == "net.fabricmc.sandbox.Main" {
// Replace the main class with the runtime entrypoint
args[i] = "net.fabricmc.sandbox.runtime.Main"
} else if args[i] == "-classpath" || args[i] == "-cp" {
// Rewrite the classpath to ensure that all of the entries are within the sandbox.
args[i + 1] = try rewriteClasspath(
args[i + 1], dotMinecraftDir: dotMinecraftDir, sandboxRoot: sandboxRoot)
args[i + 1], dotMinecraftDir: dotMinecraftDir, sandboxRoot: sandboxRoot, classpathMap: &classpathMap)
} else if args[i] == "--versionType" {
// Prefix the version type with "Sandbox", so it is clear that the game is running in a sandbox.
foundVersionType = true
Expand Down Expand Up @@ -175,12 +177,56 @@ class SandboxCommandLine {
// Remove any javaagent arguments
args.removeAll { $0.starts(with: "-javaagent") }

logger.debug("Classpath map: \(classpathMap)")

for name in ["fabric.gameJarPath", "fabric.gameJarPath.client", "fabric.gameJarPath.server"] {
SandboxCommandLine.modifyJvmProp(name: name, args: &args) { value in
let classPath = value.split(separator: ";")
var newClasspath: [String] = []

for path in classPath {
let file = File(String(path))
let newPath = classpathMap[file.path()]
if newPath == nil && file.exists() {
logger.warning("Failed to find classpath entry for \(path)")
}

newClasspath.append(newPath ?? String(path))
}

return newClasspath.joined(separator: ";")
}
}

SandboxCommandLine.modifyJvmProp(name: "fabric.classPathGroups", args: &args) { value in
let groups = value.split(separator: ";;")
var newGroups: [String] = []

for group in groups {
let classPath = group.split(separator: ";")
var newClasspath: [String] = []

for path in classPath {
let file = File(String(path))
let newPath = classpathMap[file.path()]
if newPath == nil && file.exists() {
logger.warning("Failed to find classpath entry for \(path)")
}
newClasspath.append(newPath ?? String(path))
}

newGroups.append(newClasspath.joined(separator: ";"))
}

return newGroups.joined(separator: ";;")
}

// TODO if an args file was used, we should write a new one with the updated args
return args
}

// Read the classpath from the arguments and copy the files to the sandbox, returning the new classpath.
func rewriteClasspath(_ classPathArgument: String, dotMinecraftDir: File, sandboxRoot: File)
func rewriteClasspath(_ classPathArgument: String, dotMinecraftDir: File, sandboxRoot: File, classpathMap: inout [String: String])
throws -> String
{
let classPath = classPathArgument.split(separator: ";")
Expand Down Expand Up @@ -213,11 +259,13 @@ class SandboxCommandLine {
logger.debug("Copying classpath entry to sandbox: \(source.path()) -> \(target.path())")
try source.copy(to: target)
newClasspath.append(target.path())
classpathMap[source.path()] = target.path()
} else {
// The classpath entry is located within the minecraft jar, so will be mounted into the sandbox.
let relativePath = source.relative(to: dotMinecraftDir)
let sandboxPath = sandboxRoot.child(relativePath)
newClasspath.append(sandboxPath.path())
classpathMap[source.path()] = sandboxPath.path()
}
}
return newClasspath.joined(separator: ";")
Expand Down Expand Up @@ -252,4 +300,16 @@ class SandboxCommandLine {
try newClasspathFile.writeString(newEntries.map { $0.path() }.joined(separator: ";"))
return newClasspathFile
}

private static func modifyJvmProp(name: String, args: inout [String], _ func: (String) -> String) {
let prop = "-D\(name)="
for i in 0..<args.count {
if args[i].starts(with: prop) {
args[i] = prop + `func`(String(args[i].dropFirst(prop.count)))
return
}
}

logger.debug("Failed to modify JVM property: \(name)")
}
}
2 changes: 2 additions & 0 deletions windows/Sources/Packager/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func copyDlls(_ packageDir: File, arch: Architecture, redistributables: [String:
"swiftCore.dll",
"swiftCRT.dll",
"swiftSwiftOnoneSupport.dll",
"swift_RegexParser.dll",
"swift_StringProcessing.dll",
"BlocksRuntime.dll",
"vcruntime140.dll",
"vcruntime140_1.dll",
Expand Down
37 changes: 37 additions & 0 deletions windows/Tests/CommandLineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,43 @@ struct CommandLineTests {
}
}

@Test func rewriteGameJarPath() throws {
let dummmyDotMinecraftDir = try createTempDir(ext: ".minecraft")
let dummySandboxRoot = try createTempDir(ext: ".sandbox")

defer { try! dummmyDotMinecraftDir.delete() }
defer { try! dummySandboxRoot.delete() }

let binDir = dummmyDotMinecraftDir.child("bin")
let dummyJar = binDir.child("test.jar")
try binDir.createDirectory()
try dummyJar.touch()

let commandLine = try processCommandLine(
["-cp", dummyJar.path(), "-Dfabric.gameJarPath=" + dummyJar.path()], dotMinecraftDir: dummmyDotMinecraftDir,
sandboxRoot: dummySandboxRoot)
expectContains(commandLine, ["-Dfabric.gameJarPath=" + dummySandboxRoot.child("bin").child("test.jar").path()])
}

@Test func rewriteClasspathGroups() throws {
let dummmyDotMinecraftDir = try createTempDir(ext: ".minecraft")
let dummySandboxRoot = try createTempDir(ext: ".sandbox")

defer { try! dummmyDotMinecraftDir.delete() }
defer { try! dummySandboxRoot.delete() }

let binDir = dummmyDotMinecraftDir.child("bin")
let dummyJar = binDir.child("test.jar")
try binDir.createDirectory()
try dummyJar.touch()

let commandLine = try processCommandLine(
["-cp", dummyJar.path(), "-Dfabric.classPathGroups=" + dummyJar.path() + ";" + dummyJar.path() + ";;test.jar"], dotMinecraftDir: dummmyDotMinecraftDir,
sandboxRoot: dummySandboxRoot)
let sbPath = dummySandboxRoot.child("bin").child("test.jar").path()
expectContains(commandLine, ["-Dfabric.classPathGroups=" + sbPath + ";" + sbPath + ";;test.jar"])
}

private func processCommandLine(
_ args: [String], dotMinecraftDir: File = File("C:/.minecraft"),
sandboxRoot: File = File("S:"),
Expand Down

0 comments on commit 8690ca5

Please sign in to comment.