Resolve assembly paths before loading the FileSystem.
This commit is contained in:
@@ -297,5 +297,40 @@ namespace OpenRA.FileSystem
|
|||||||
|
|
||||||
return fileIndex.ContainsKey(filename);
|
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];
|
Languages = new string[0];
|
||||||
|
|
||||||
ModFiles = new FS(mods);
|
|
||||||
|
|
||||||
// Take a local copy of the manifest
|
// Take a local copy of the manifest
|
||||||
Manifest = new Manifest(mod.Id, mod.Package);
|
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);
|
Manifest.LoadCustomData(ObjectCreator);
|
||||||
|
|
||||||
if (useLoadScreen)
|
if (useLoadScreen)
|
||||||
|
|||||||
@@ -27,40 +27,31 @@ namespace OpenRA
|
|||||||
readonly Cache<string, Type> typeCache;
|
readonly Cache<string, Type> typeCache;
|
||||||
readonly Cache<Type, ConstructorInfo> ctorCache;
|
readonly Cache<Type, ConstructorInfo> ctorCache;
|
||||||
readonly Pair<Assembly, string>[] assemblies;
|
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);
|
typeCache = new Cache<string, Type>(FindType);
|
||||||
ctorCache = new Cache<Type, ConstructorInfo>(GetCtor);
|
ctorCache = new Cache<Type, ConstructorInfo>(GetCtor);
|
||||||
|
|
||||||
// Allow mods to load types from the core Game assembly, and any additional assemblies they specify.
|
// 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 };
|
var assemblyList = new List<Assembly>() { typeof(Game).Assembly };
|
||||||
foreach (var path in manifest.Assemblies)
|
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:
|
// .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.
|
// (a) loading duplicate data into the application domain, breaking the world.
|
||||||
// (b) crashing if the assembly has already been loaded.
|
// (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
|
// 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;
|
Assembly assembly;
|
||||||
if (!ResolvedAssemblies.TryGetValue(hash, out assembly))
|
if (!ResolvedAssemblies.TryGetValue(hash, out assembly))
|
||||||
{
|
{
|
||||||
Stream symbolStream = null;
|
assembly = Assembly.LoadFile(resolvedPath);
|
||||||
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);
|
|
||||||
ResolvedAssemblies.Add(hash, assembly);
|
ResolvedAssemblies.Add(hash, assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user