mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
* Scripting hotfix - Fixes #2458 - Change error wording around scripting - Prevent duplicating the binary for scripting * Create temporary folder if it doesn't exist
This commit is contained in:
parent
2f1da9e8c9
commit
74d29321b4
1 changed files with 63 additions and 46 deletions
|
|
@ -82,57 +82,74 @@ namespace MinecraftClient.Scripting.DynamicRun.Builder
|
||||||
if (string.IsNullOrEmpty(MinecraftClientDll))
|
if (string.IsNullOrEmpty(MinecraftClientDll))
|
||||||
{
|
{
|
||||||
// Create a temporary file to copy the executable to.
|
// Create a temporary file to copy the executable to.
|
||||||
var executableDir = AppContext.BaseDirectory;
|
var executablePath = Environment.ProcessPath;
|
||||||
var executablePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Path.Combine(executableDir, "MinecraftClient.exe") : Path.Combine(executableDir, "MinecraftClient");
|
var tempPath = Path.Combine(Path.GetTempPath(), "mcc-scripting");
|
||||||
var tempFileName = Path.GetTempFileName();
|
Directory.CreateDirectory(tempPath);
|
||||||
if (File.Exists(executablePath))
|
|
||||||
|
var tempFile = Path.Combine(tempPath, "mcc-executable");
|
||||||
|
var useExisting = false;
|
||||||
|
|
||||||
|
// Check if we already have the executable in the temporary path.
|
||||||
|
foreach (var file in Directory.EnumerateFiles(tempPath))
|
||||||
{
|
{
|
||||||
// Copy the executable to a temporary path.
|
if (file.EndsWith("mcc-executable"))
|
||||||
ExecutableReader e = new();
|
|
||||||
File.Delete(tempFileName);
|
|
||||||
File.Copy(executablePath, tempFileName);
|
|
||||||
|
|
||||||
// Access the contents of the executable.
|
|
||||||
var viewAccessor = MemoryMappedFile.CreateFromFile(tempFileName, FileMode.Open).CreateViewAccessor();
|
|
||||||
var manifest = e.ReadManifest(viewAccessor);
|
|
||||||
var files = manifest.Files;
|
|
||||||
|
|
||||||
Stream? assemblyStream;
|
|
||||||
|
|
||||||
var assemblyrefs = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().ToList()!;
|
|
||||||
assemblyrefs.Add(new("MinecraftClient"));
|
|
||||||
assemblyrefs.Add(new("System.Private.CoreLib"));
|
|
||||||
|
|
||||||
foreach (var refs in assemblyrefs)
|
|
||||||
{
|
{
|
||||||
var loadedAssembly = Assembly.Load(refs);
|
useExisting = true;
|
||||||
if (string.IsNullOrEmpty(loadedAssembly.Location))
|
break;
|
||||||
{
|
}
|
||||||
// Check if we can access the file from the executable.
|
}
|
||||||
var reference = files.FirstOrDefault(x => x.RelativePath.Remove(x.RelativePath.Length - 4) == refs.Name);
|
|
||||||
var refCount = files.Count(x => x.RelativePath.Remove(x.RelativePath.Length - 4) == refs.Name);
|
|
||||||
if (refCount > 1)
|
|
||||||
{
|
|
||||||
// Safety net for the case where the assembly is referenced multiple times.
|
|
||||||
// Should not happen normally, but we can make exceptions when it does happen.
|
|
||||||
throw new InvalidOperationException("Too many references to the same assembly. Assembly name: " + refs.Name);
|
|
||||||
}
|
|
||||||
if (reference == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("The executable does not contain a referenced assembly. Assembly name: " + refs.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
assemblyStream = GetStreamForFileEntry(viewAccessor, reference);
|
if (!File.Exists(executablePath))
|
||||||
references.Add(MetadataReference.CreateFromStream(assemblyStream!));
|
{
|
||||||
continue;
|
throw new FileNotFoundException("[Script Error] Could not locate the current folder of MCC for scripting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the executable to a temporary path.
|
||||||
|
if (!useExisting)
|
||||||
|
File.Copy(executablePath, tempFile);
|
||||||
|
|
||||||
|
// Access the contents of the executable.
|
||||||
|
ExecutableReader e = new();
|
||||||
|
var viewAccessor = MemoryMappedFile.CreateFromFile(tempFile, FileMode.Open).CreateViewAccessor();
|
||||||
|
var manifest = e.ReadManifest(viewAccessor);
|
||||||
|
var files = manifest.Files;
|
||||||
|
|
||||||
|
Stream? assemblyStream;
|
||||||
|
|
||||||
|
var assemblyrefs = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().ToList()!;
|
||||||
|
assemblyrefs.Add(new("MinecraftClient"));
|
||||||
|
assemblyrefs.Add(new("System.Private.CoreLib"));
|
||||||
|
|
||||||
|
foreach (var refs in assemblyrefs) {
|
||||||
|
var loadedAssembly = Assembly.Load(refs);
|
||||||
|
if (string.IsNullOrEmpty(loadedAssembly.Location)) {
|
||||||
|
// Check if we can access the file from the executable.
|
||||||
|
var reference = files.FirstOrDefault(x =>
|
||||||
|
x.RelativePath.Remove(x.RelativePath.Length - 4) == refs.Name);
|
||||||
|
var refCount = files.Count(x => x.RelativePath.Remove(x.RelativePath.Length - 4) == refs.Name);
|
||||||
|
if (refCount > 1) {
|
||||||
|
// Safety net for the case where the assembly is referenced multiple times.
|
||||||
|
// Should not happen normally, but we can make exceptions when it does happen.
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"[Script Error] Too many references to the same assembly. Assembly name: " + refs.Name);
|
||||||
}
|
}
|
||||||
references.Add(MetadataReference.CreateFromFile(loadedAssembly.Location));
|
|
||||||
|
if (reference == null) {
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"[Script Error] The executable does not contain a referenced assembly. Assembly name: " + refs.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
assemblyStream = GetStreamForFileEntry(viewAccessor, reference);
|
||||||
|
references.Add(MetadataReference.CreateFromStream(assemblyStream!));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup.
|
references.Add(MetadataReference.CreateFromFile(loadedAssembly.Location));
|
||||||
viewAccessor.Flush();
|
|
||||||
viewAccessor.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup.
|
||||||
|
viewAccessor.Flush();
|
||||||
|
viewAccessor.Dispose();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -154,7 +171,7 @@ namespace MinecraftClient.Scripting.DynamicRun.Builder
|
||||||
private static Stream? GetStreamForFileEntry(MemoryMappedViewAccessor viewAccessor, FileEntry file)
|
private static Stream? GetStreamForFileEntry(MemoryMappedViewAccessor viewAccessor, FileEntry file)
|
||||||
{
|
{
|
||||||
if (typeof(BundleExtractor).GetMethod("GetStreamForFileEntry", BindingFlags.NonPublic | BindingFlags.Static)!.Invoke(null, new object[] { viewAccessor, file }) is not Stream stream)
|
if (typeof(BundleExtractor).GetMethod("GetStreamForFileEntry", BindingFlags.NonPublic | BindingFlags.Static)!.Invoke(null, new object[] { viewAccessor, file }) is not Stream stream)
|
||||||
throw new InvalidOperationException("The executable does not contain the assembly. Assembly name: " + file.RelativePath);
|
throw new InvalidOperationException("[Script Error] The executable does not contain the assembly. Assembly name: " + file.RelativePath);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue