ClientScript loading logic
This commit is contained in:
@ -49,7 +49,7 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Main.Logger.Error("Error occurred when loading server resource:");
|
Main.Logger.Error("Error occurred when loading server resource");
|
||||||
Main.Logger.Error(ex);
|
Main.Logger.Error(ex);
|
||||||
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.LoadFailed };
|
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.LoadFailed };
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ using System.Resources;
|
|||||||
|
|
||||||
|
|
||||||
// Version informationr(
|
// Version informationr(
|
||||||
[assembly: AssemblyVersion("1.5.4.184")]
|
[assembly: AssemblyVersion("1.5.4.186")]
|
||||||
[assembly: AssemblyFileVersion("1.5.4.184")]
|
[assembly: AssemblyFileVersion("1.5.4.186")]
|
||||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using RageCoop.Core;
|
|||||||
using RageCoop.Core.Scripting;
|
using RageCoop.Core.Scripting;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace RageCoop.Client.Scripting
|
namespace RageCoop.Client.Scripting
|
||||||
@ -214,6 +215,13 @@ namespace RageCoop.Client.Scripting
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region FUNCTIONS
|
#region FUNCTIONS
|
||||||
|
public ClientResource GetResource(string name)
|
||||||
|
{
|
||||||
|
if(Main.Resources.LoadedResources.TryGetValue(name.ToLower(), out var res)){
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connect to a server
|
/// Connect to a server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -14,12 +14,12 @@ namespace RageCoop.Client.Scripting
|
|||||||
protected static API API => Main.API;
|
protected static API API => Main.API;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method would be called from background thread, call <see cref="API.QueueAction(System.Action)"/> to dispatch it to main thread.
|
/// This method would be called from main thread, right after the constructor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void OnStart();
|
public abstract void OnStart();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method would be called from background thread when the client disconnected from the server, you MUST terminate all background jobs/threads in this method.
|
/// This method would be called from main thread right before the whole <see cref="System.AppDomain"/> is unloded but prior to <see cref="GTA.Script.Aborted"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void OnStop();
|
public abstract void OnStop();
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Windows.Forms;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using static System.Net.WebRequestMethods;
|
||||||
|
|
||||||
namespace RageCoop.Client.Scripting
|
namespace RageCoop.Client.Scripting
|
||||||
{
|
{
|
||||||
@ -36,6 +37,8 @@ namespace RageCoop.Client.Scripting
|
|||||||
// Bridge to current ScriptDomain
|
// Bridge to current ScriptDomain
|
||||||
primary.Tick += Tick;
|
primary.Tick += Tick;
|
||||||
primary.KeyEvent += KeyEvent;
|
primary.KeyEvent += KeyEvent;
|
||||||
|
CurrentDomain.Start();
|
||||||
|
SetupScripts();
|
||||||
AppDomain.CurrentDomain.SetData("Primary", false);
|
AppDomain.CurrentDomain.SetData("Primary", false);
|
||||||
Console.WriteLine("Loaded scondary domain: " + AppDomain.CurrentDomain.Id + " " + Util.IsPrimaryDomain);
|
Console.WriteLine("Loaded scondary domain: " + AppDomain.CurrentDomain.Id + " " + Util.IsPrimaryDomain);
|
||||||
}
|
}
|
||||||
@ -45,10 +48,31 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
public void SetupScripts()
|
public void SetupScripts()
|
||||||
{
|
{
|
||||||
foreach(var s in ScriptDomain.CurrentDomain.RunningScripts)
|
foreach (var s in GetClientScripts())
|
||||||
{
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var script = (ClientScript)s;
|
||||||
|
var res = Main.API.GetResource(Path.GetFileName(Directory.GetParent(script.Filename).FullName));
|
||||||
|
if (res == null) { Main.API.Logger.Warning("Failed to locate resource for script: " + script.Filename); continue; }
|
||||||
|
script.CurrentResource = res;
|
||||||
|
script.CurrentFile = res.Files.Values.Where(x => x.Name.ToLower() == script.Filename.Substring(res.BaseDirectory.Length + 1).Replace('\\', '/')).FirstOrDefault();
|
||||||
|
res.Scripts.Add(script);
|
||||||
|
script.OnStart();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Main.API.Logger.Error($"Failed to start {s.GetType().FullName}", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public object[] GetClientScripts()
|
||||||
|
{
|
||||||
|
return ScriptDomain.CurrentDomain.RunningScripts.Where(x =>
|
||||||
|
x.ScriptInstance.GetType().IsAssignableFrom(typeof(ClientScript)) &&
|
||||||
|
!x.ScriptInstance.GetType().IsAbstract).Select(x => x.ScriptInstance).ToArray();
|
||||||
|
}
|
||||||
public static ResourceDomain Load(string dir = @"RageCoop\Scripts\Debug")
|
public static ResourceDomain Load(string dir = @"RageCoop\Scripts\Debug")
|
||||||
{
|
{
|
||||||
lock (_loadedDomains)
|
lock (_loadedDomains)
|
||||||
@ -62,7 +86,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
throw new Exception("Already loaded");
|
throw new Exception("Already loaded");
|
||||||
}
|
}
|
||||||
ScriptDomain domain = null;
|
ScriptDomain sDomain = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dir = Path.GetFullPath(dir);
|
dir = Path.GetFullPath(dir);
|
||||||
@ -81,11 +105,10 @@ namespace RageCoop.Client.Scripting
|
|||||||
.Select(x => Assembly.Load(x.FullName).Location)
|
.Select(x => Assembly.Load(x.FullName).Location)
|
||||||
.Where(x => !string.IsNullOrEmpty(x)));
|
.Where(x => !string.IsNullOrEmpty(x)));
|
||||||
|
|
||||||
domain = ScriptDomain.Load(Directory.GetParent(typeof(ScriptDomain).Assembly.Location).FullName, dir);
|
sDomain = ScriptDomain.Load(Directory.GetParent(typeof(ScriptDomain).Assembly.Location).FullName, dir);
|
||||||
domain.AppDomain.SetData("Console", ScriptDomain.CurrentDomain.AppDomain.GetData("Console"));
|
sDomain.AppDomain.SetData("Console", ScriptDomain.CurrentDomain.AppDomain.GetData("Console"));
|
||||||
domain.AppDomain.SetData("RageCoop.Client.API", API.GetInstance());
|
sDomain.AppDomain.SetData("RageCoop.Client.API", API.GetInstance());
|
||||||
_loadedDomains.TryAdd(dir, (ResourceDomain)domain.AppDomain.CreateInstanceFromAndUnwrap(typeof(ResourceDomain).Assembly.Location, typeof(ResourceDomain).FullName, false, BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { ScriptDomain.CurrentDomain, api.ToArray() }, null, null));
|
_loadedDomains.TryAdd(dir, (ResourceDomain)sDomain.AppDomain.CreateInstanceFromAndUnwrap(typeof(ResourceDomain).Assembly.Location, typeof(ResourceDomain).FullName, false, BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { ScriptDomain.CurrentDomain, api.ToArray() }, null, null));
|
||||||
domain.Start();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait till next tick
|
// Wait till next tick
|
||||||
@ -96,9 +119,9 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
GTA.UI.Notification.Show(ex.ToString());
|
GTA.UI.Notification.Show(ex.ToString());
|
||||||
Main.Logger.Error(ex);
|
Main.Logger.Error(ex);
|
||||||
if (domain != null)
|
if (sDomain != null)
|
||||||
{
|
{
|
||||||
ScriptDomain.Unload(domain);
|
ScriptDomain.Unload(sDomain);
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@ -109,13 +132,19 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
lock (_loadedDomains)
|
lock (_loadedDomains)
|
||||||
{
|
{
|
||||||
|
Exception ex=null;
|
||||||
Main.QueueToMainThread(() =>
|
Main.QueueToMainThread(() =>
|
||||||
{
|
{
|
||||||
domain.Dispose();
|
try
|
||||||
ScriptDomain.Unload(domain.CurrentDomain);
|
{
|
||||||
_loadedDomains.TryRemove(domain.BaseDirectory, out _);
|
domain.Dispose();
|
||||||
|
ScriptDomain.Unload(domain.CurrentDomain);
|
||||||
|
_loadedDomains.TryRemove(domain.BaseDirectory, out _);
|
||||||
|
}
|
||||||
|
catch(Exception e) { ex = e; }
|
||||||
});
|
});
|
||||||
GTA.Script.Yield();
|
GTA.Script.Yield();
|
||||||
|
if(ex != null) { throw ex; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Unload(string dir)
|
public static void Unload(string dir)
|
||||||
@ -145,6 +174,17 @@ namespace RageCoop.Client.Scripting
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
foreach(var s in GetClientScripts())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
((ClientScript)s).OnStop();
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Main.API.Logger.Error($"Failed to stop {s.GetType().FullName}",ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
PrimaryDomain.Tick -= Tick;
|
PrimaryDomain.Tick -= Tick;
|
||||||
PrimaryDomain.KeyEvent -= KeyEvent;
|
PrimaryDomain.KeyEvent -= KeyEvent;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using RageCoop.Core.Scripting;
|
using RageCoop.Core.Scripting;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -18,10 +19,11 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// Name of the resource
|
/// Name of the resource
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; internal set; }
|
public string Name { get; internal set; }
|
||||||
|
public string BaseDirectory { get; internal set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A resource-specific folder that can be used to store your files.
|
/// A resource-specific folder that can be used to store your files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DataFolder { get; internal set; }
|
public string DataFolder => Path.Combine(BaseDirectory, "Data");
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all <see cref="ClientScript"/> instance in this resource.
|
/// Get all <see cref="ClientScript"/> instance in this resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -39,56 +41,13 @@ namespace RageCoop.Client.Scripting
|
|||||||
internal class Resources
|
internal class Resources
|
||||||
{
|
{
|
||||||
static readonly API API = Main.API;
|
static readonly API API = Main.API;
|
||||||
private readonly List<ClientResource> LoadedResources = new List<ClientResource>();
|
internal readonly ConcurrentDictionary<string, ClientResource> LoadedResources = new ConcurrentDictionary<string, ClientResource>();
|
||||||
private const string BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
|
private const string BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
|
||||||
private Logger Logger { get; set; }
|
private Logger Logger { get; set; }
|
||||||
public Resources()
|
public Resources()
|
||||||
{
|
{
|
||||||
Logger = Main.Logger;
|
Logger = Main.Logger;
|
||||||
}
|
}
|
||||||
private void StartAll()
|
|
||||||
{
|
|
||||||
lock (LoadedResources)
|
|
||||||
{
|
|
||||||
foreach (var d in LoadedResources)
|
|
||||||
{
|
|
||||||
foreach (var s in d.Scripts)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
s.CurrentResource = d;
|
|
||||||
s.OnStart();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error("Error occurred when starting script:" + s.GetType().FullName);
|
|
||||||
Logger?.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void StopAll()
|
|
||||||
{
|
|
||||||
lock (LoadedResources)
|
|
||||||
{
|
|
||||||
foreach (var d in LoadedResources)
|
|
||||||
{
|
|
||||||
foreach (var s in d.Scripts)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
s.OnStop();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error("Error occurred when stopping script:" + s.GetType().FullName);
|
|
||||||
Logger?.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Load(string path, string[] zips)
|
public void Load(string path, string[] zips)
|
||||||
{
|
{
|
||||||
LoadedResources.Clear();
|
LoadedResources.Clear();
|
||||||
@ -96,166 +55,56 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
var zipPath = Path.Combine(path, zip);
|
var zipPath = Path.Combine(path, zip);
|
||||||
Logger?.Info($"Loading resource: {Path.GetFileNameWithoutExtension(zip)}");
|
Logger?.Info($"Loading resource: {Path.GetFileNameWithoutExtension(zip)}");
|
||||||
LoadResource(new ZipFile(zipPath), Path.Combine(path, "data"));
|
Unpack(zipPath, Path.Combine(path, "Data"));
|
||||||
}
|
}
|
||||||
StartAll();
|
ResourceDomain.Load(path);
|
||||||
}
|
}
|
||||||
public void Unload()
|
public void Unload()
|
||||||
{
|
{
|
||||||
StopAll();
|
|
||||||
ResourceDomain.UnloadAll();
|
ResourceDomain.UnloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadResource(ZipFile file, string dataFolderRoot)
|
private void Unpack(string zipPath, string dataFolderRoot)
|
||||||
{
|
{
|
||||||
List<Action> toLoad = new List<Action>(10);
|
|
||||||
var r = new ClientResource()
|
var r = new ClientResource()
|
||||||
{
|
{
|
||||||
Logger = Main.Logger,
|
Logger = Main.API.Logger,
|
||||||
Scripts = new List<ClientScript>(),
|
Scripts = new List<ClientScript>(),
|
||||||
Name = Path.GetFileNameWithoutExtension(file.Name),
|
Name = Path.GetFileNameWithoutExtension(zipPath),
|
||||||
DataFolder = Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
|
BaseDirectory = Path.Combine(Directory.GetParent(zipPath).FullName, Path.GetFileNameWithoutExtension(zipPath))
|
||||||
};
|
};
|
||||||
Directory.CreateDirectory(r.DataFolder);
|
Directory.CreateDirectory(r.DataFolder);
|
||||||
|
var resDir = r.BaseDirectory;
|
||||||
|
if (Directory.Exists(resDir)) { Directory.Delete(resDir, true); }
|
||||||
|
else if (File.Exists(resDir)) { File.Delete(resDir); }
|
||||||
|
Directory.CreateDirectory(resDir);
|
||||||
|
|
||||||
foreach (ZipEntry entry in file)
|
new FastZip().ExtractZip(zipPath, resDir, null);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var dir in Directory.GetDirectories(resDir, "*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
ResourceFile rFile;
|
r.Files.Add(dir, new ResourceFile()
|
||||||
r.Files.Add(entry.Name, rFile = new ResourceFile()
|
|
||||||
{
|
{
|
||||||
Name = entry.Name,
|
IsDirectory = true,
|
||||||
IsDirectory = entry.IsDirectory,
|
Name = dir.Substring(resDir.Length + 1).Replace('\\', '/')
|
||||||
});
|
});
|
||||||
if (!entry.IsDirectory)
|
}
|
||||||
|
var assemblies = new Dictionary<ResourceFile, Assembly>();
|
||||||
|
foreach (var file in Directory.GetFiles(resDir, "*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
if (Path.GetFileName(file).CanBeIgnored()) { try { File.Delete(file); } catch { } continue; }
|
||||||
|
var relativeName = file.Substring(resDir.Length + 1).Replace('\\', '/');
|
||||||
|
var rfile = new ResourceFile()
|
||||||
{
|
{
|
||||||
rFile.GetStream = () => { return file.GetInputStream(entry); };
|
GetStream = () => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
|
||||||
if (entry.Name.EndsWith(".dll") && !entry.Name.Contains("/"))
|
IsDirectory = false,
|
||||||
{
|
Name = relativeName
|
||||||
// Don't load API assembly
|
};
|
||||||
if (Path.GetFileName(entry.Name).CanBeIgnored()) { continue; }
|
r.Files.Add(relativeName, rfile);
|
||||||
var tmp = Path.GetTempFileName();
|
|
||||||
var f = File.OpenWrite(tmp);
|
|
||||||
rFile.GetStream().CopyTo(f);
|
|
||||||
f.Close();
|
|
||||||
if (!IsManagedAssembly(tmp))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var asm = Assembly.LoadFrom(tmp);
|
|
||||||
toLoad.Add(() => LoadScriptsFromAssembly(rFile, asm, entry.Name, r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var a in toLoad)
|
|
||||||
{
|
|
||||||
a();
|
|
||||||
}
|
|
||||||
LoadedResources.Add(r);
|
|
||||||
file.Close();
|
|
||||||
}
|
|
||||||
private bool LoadScriptsFromAssembly(ResourceFile rfile, Assembly assembly, string filename, ClientResource toload)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Find all script types in the assembly
|
|
||||||
foreach (var type in assembly.GetTypes().Where(x => IsSubclassOf(x, BaseScriptType)))
|
|
||||||
{
|
|
||||||
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
|
|
||||||
if (constructor != null && constructor.IsPublic)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Invoke script constructor
|
|
||||||
var script = constructor.Invoke(null) as ClientScript;
|
|
||||||
// script.CurrentResource = toload;
|
|
||||||
script.CurrentFile = rfile;
|
|
||||||
script.CurrentResource = toload;
|
|
||||||
toload.Scripts.Add(script);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
|
|
||||||
Logger?.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ReflectionTypeLoadException ex)
|
|
||||||
{
|
|
||||||
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
|
|
||||||
Logger?.Error(ex);
|
|
||||||
foreach (var e in ex.LoaderExceptions)
|
|
||||||
{
|
|
||||||
Logger?.Error(e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
|
LoadedResources.TryAdd(r.Name.ToLower(), r);
|
||||||
return count != 0;
|
|
||||||
}
|
|
||||||
private bool IsManagedAssembly(string filename)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
|
||||||
{
|
|
||||||
if (file.Length < 64)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
using (BinaryReader bin = new BinaryReader(file))
|
|
||||||
{
|
|
||||||
// PE header starts at offset 0x3C (60). Its a 4 byte header.
|
|
||||||
file.Position = 0x3C;
|
|
||||||
uint offset = bin.ReadUInt32();
|
|
||||||
if (offset == 0)
|
|
||||||
offset = 0x80;
|
|
||||||
|
|
||||||
// Ensure there is at least enough room for the following structures:
|
|
||||||
// 24 byte PE Signature & Header
|
|
||||||
// 28 byte Standard Fields (24 bytes for PE32+)
|
|
||||||
// 68 byte NT Fields (88 bytes for PE32+)
|
|
||||||
// >= 128 byte Data Dictionary Table
|
|
||||||
if (offset > file.Length - 256)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check the PE signature. Should equal 'PE\0\0'.
|
|
||||||
file.Position = offset;
|
|
||||||
if (bin.ReadUInt32() != 0x00004550)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Read PE magic number from Standard Fields to determine format.
|
|
||||||
file.Position += 20;
|
|
||||||
var peFormat = bin.ReadUInt16();
|
|
||||||
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
|
|
||||||
// When this is non-zero then the file contains CLI data otherwise not.
|
|
||||||
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
|
|
||||||
return bin.ReadUInt32() != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// This is likely not a valid assembly if any IO exceptions occur during reading
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool IsSubclassOf(Type type, string baseTypeName)
|
|
||||||
{
|
|
||||||
for (Type t = type.BaseType; t != null; t = t.BaseType)
|
|
||||||
if (t.FullName == baseTypeName)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
return ToIgnore.Contains(Path.GetFileNameWithoutExtension(name));
|
return ToIgnore.Contains(Path.GetFileNameWithoutExtension(name));
|
||||||
}
|
}
|
||||||
|
public static string ToFullPath(this string path)
|
||||||
|
{
|
||||||
|
return Path.GetFullPath(path);
|
||||||
|
}
|
||||||
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
|
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
switch (obj)
|
switch (obj)
|
||||||
|
@ -59,7 +59,7 @@ namespace RageCoop.Server.Scripting
|
|||||||
{
|
{
|
||||||
IsDirectory = true,
|
IsDirectory = true,
|
||||||
Name = dir.Substring(resDir.Length + 1).Replace('\\', '/')
|
Name = dir.Substring(resDir.Length + 1).Replace('\\', '/')
|
||||||
}); ;
|
});
|
||||||
}
|
}
|
||||||
var assemblies = new Dictionary<ResourceFile, Assembly>();
|
var assemblies = new Dictionary<ResourceFile, Assembly>();
|
||||||
foreach (var file in Directory.GetFiles(resDir, "*", SearchOption.AllDirectories))
|
foreach (var file in Directory.GetFiles(resDir, "*", SearchOption.AllDirectories))
|
||||||
|
Reference in New Issue
Block a user