Resolve assembly paths before loading the FileSystem.
This commit is contained in:
@@ -297,5 +297,40 @@ namespace OpenRA.FileSystem
|
||||
|
||||
return fileIndex.ContainsKey(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a filesystem for an assembly, accounting for explicit and mod mounts.
|
||||
/// Assemblies must exist in the native OS file system (not inside an OpenRA-defined package).
|
||||
/// </summary>
|
||||
public static string ResolveAssemblyPath(string path, Manifest manifest, InstalledMods installedMods)
|
||||
{
|
||||
var explicitSplit = path.IndexOf('|');
|
||||
if (explicitSplit > 0)
|
||||
{
|
||||
var parent = path.Substring(0, explicitSplit);
|
||||
var filename = path.Substring(explicitSplit + 1);
|
||||
|
||||
var parentPath = manifest.Packages.FirstOrDefault(kv => kv.Value == parent).Key;
|
||||
if (parentPath == null)
|
||||
return null;
|
||||
|
||||
if (parentPath.StartsWith("$", StringComparison.Ordinal))
|
||||
{
|
||||
Manifest mod;
|
||||
if (!installedMods.TryGetValue(parentPath.Substring(1), out mod))
|
||||
return null;
|
||||
|
||||
if (!(mod.Package is Folder))
|
||||
return null;
|
||||
|
||||
path = Path.Combine(mod.Package.Name, filename);
|
||||
}
|
||||
else
|
||||
path = Path.Combine(parentPath, filename);
|
||||
}
|
||||
|
||||
var resolvedPath = Platform.ResolvePath(path);
|
||||
return File.Exists(resolvedPath) ? resolvedPath : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,13 @@ namespace OpenRA
|
||||
{
|
||||
Languages = new string[0];
|
||||
|
||||
ModFiles = new FS(mods);
|
||||
|
||||
// Take a local copy of the manifest
|
||||
Manifest = new Manifest(mod.Id, mod.Package);
|
||||
ModFiles.LoadFromManifest(Manifest);
|
||||
ObjectCreator = new ObjectCreator(Manifest, mods);
|
||||
|
||||
ObjectCreator = new ObjectCreator(Manifest, ModFiles);
|
||||
ModFiles = new FS(mods);
|
||||
ModFiles.LoadFromManifest(Manifest);
|
||||
Manifest.LoadCustomData(ObjectCreator);
|
||||
|
||||
if (useLoadScreen)
|
||||
|
||||
@@ -27,40 +27,31 @@ namespace OpenRA
|
||||
readonly Cache<string, Type> typeCache;
|
||||
readonly Cache<Type, ConstructorInfo> ctorCache;
|
||||
readonly Pair<Assembly, string>[] assemblies;
|
||||
readonly bool isMonoRuntime = Type.GetType("Mono.Runtime") != null;
|
||||
|
||||
public ObjectCreator(Manifest manifest, FileSystem.FileSystem modFiles)
|
||||
public ObjectCreator(Manifest manifest, InstalledMods mods)
|
||||
{
|
||||
typeCache = new Cache<string, Type>(FindType);
|
||||
ctorCache = new Cache<Type, ConstructorInfo>(GetCtor);
|
||||
|
||||
// Allow mods to load types from the core Game assembly, and any additional assemblies they specify.
|
||||
// Assemblies can only be loaded from directories to avoid circular dependencies on package loaders.
|
||||
var assemblyList = new List<Assembly>() { typeof(Game).Assembly };
|
||||
foreach (var path in manifest.Assemblies)
|
||||
{
|
||||
var data = modFiles.Open(path).ReadAllBytes();
|
||||
var resolvedPath = FileSystem.FileSystem.ResolveAssemblyPath(path, manifest, mods);
|
||||
if (resolvedPath == null)
|
||||
throw new FileNotFoundException("Assembly `{0}` not found.".F(path));
|
||||
|
||||
// .NET doesn't provide any way of querying the metadata of an assembly without either:
|
||||
// (a) loading duplicate data into the application domain, breaking the world.
|
||||
// (b) crashing if the assembly has already been loaded.
|
||||
// We can't check the internal name of the assembly, so we'll work off the data instead
|
||||
var hash = CryptoUtil.SHA1Hash(data);
|
||||
var hash = CryptoUtil.SHA1Hash(File.ReadAllBytes(resolvedPath));
|
||||
|
||||
Assembly assembly;
|
||||
if (!ResolvedAssemblies.TryGetValue(hash, out assembly))
|
||||
{
|
||||
Stream symbolStream = null;
|
||||
var hasSymbols = false;
|
||||
|
||||
// Mono has its own symbol format.
|
||||
if (isMonoRuntime)
|
||||
hasSymbols = modFiles.TryOpen(path + ".mdb", out symbolStream);
|
||||
|
||||
// .NET uses .pdb files.
|
||||
else
|
||||
hasSymbols = modFiles.TryOpen(path.Substring(0, path.Length - 4) + ".pdb", out symbolStream);
|
||||
|
||||
assembly = hasSymbols ? Assembly.Load(data, symbolStream.ReadAllBytes()) : Assembly.Load(data);
|
||||
assembly = Assembly.LoadFile(resolvedPath);
|
||||
ResolvedAssemblies.Add(hash, assembly);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user