Skip to content

Commit

Permalink
Merge branch 'master' of github.com:milutinke/Minecraft-Console-Client
Browse files Browse the repository at this point in the history
  • Loading branch information
milutinke committed Mar 29, 2023
2 parents 978dc4b + 3f9fd47 commit 2a82c35
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 59 deletions.
109 changes: 63 additions & 46 deletions MinecraftClient/Scripting/DynamicRun/Builder/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,60 +79,77 @@ private static CSharpCompilation GenerateCode(string sourceCode, string fileName
var MinecraftClientDll = typeof(Program).Assembly.Location; // The path to MinecraftClient.dll

// We're on a self-contained binary, so we need to extract the executable to get the assemblies.
if (string.IsNullOrEmpty(MinecraftClientDll))
if (string.IsNullOrEmpty(MinecraftClientDll))
{
// Create a temporary file to copy the executable to.
var executableDir = AppContext.BaseDirectory;
var executablePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Path.Combine(executableDir, "MinecraftClient.exe") : Path.Combine(executableDir, "MinecraftClient");
var tempFileName = Path.GetTempFileName();
if (File.Exists(executablePath))
var executablePath = Environment.ProcessPath;
var tempPath = Path.Combine(Path.GetTempPath(), "mcc-scripting");
Directory.CreateDirectory(tempPath);

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.
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;
if (file.EndsWith("mcc-executable"))
{
useExisting = true;
break;
}
}

if (!File.Exists(executablePath))
{
throw new FileNotFoundException("[Script Error] Could not locate the current folder of MCC for scripting.");
}

var assemblyrefs = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().ToList()!;
assemblyrefs.Add(new("MinecraftClient"));
assemblyrefs.Add(new("System.Private.CoreLib"));
// 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);
}

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("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);
references.Add(MetadataReference.CreateFromStream(assemblyStream!));
continue;
if (reference == null) {
throw new InvalidOperationException(
"[Script Error] The executable does not contain a referenced assembly. Assembly name: " + refs.Name);
}
references.Add(MetadataReference.CreateFromFile(loadedAssembly.Location));

assemblyStream = GetStreamForFileEntry(viewAccessor, reference);
references.Add(MetadataReference.CreateFromStream(assemblyStream!));
continue;
}

// Cleanup.
viewAccessor.Flush();
viewAccessor.Dispose();
references.Add(MetadataReference.CreateFromFile(loadedAssembly.Location));
}

// Cleanup.
viewAccessor.Flush();
viewAccessor.Dispose();
}
else
{
Expand All @@ -154,7 +171,7 @@ private static CSharpCompilation GenerateCode(string sourceCode, string fileName
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)
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;
}
Expand Down
26 changes: 13 additions & 13 deletions MinecraftClient/UpgradeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,27 +241,27 @@ private static string GetOSIdentifier()
{
string OSPlatformName;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
OSPlatformName = "Windows";
OSPlatformName = "win";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
OSPlatformName = "Linux";
OSPlatformName = "linux";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
OSPlatformName = "OSX";
OSPlatformName = "osx";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
OSPlatformName = "FreeBSD";
OSPlatformName = "freebsd";
else
return string.Empty;

string architecture = RuntimeInformation.ProcessArchitecture switch
{
Architecture.X86 => "X86",
Architecture.X64 => "X64",
Architecture.Arm => "Arm32",
Architecture.Arm64 => "Arm64",
Architecture.Wasm => "Wasm",
Architecture.S390x => "S390x",
Architecture.LoongArch64 => "LoongArch64",
Architecture.Armv6 => "Armv6",
Architecture.Ppc64le => "Ppc64le",
Architecture.X86 => "x86",
Architecture.X64 => "x64",
Architecture.Arm => "arm32",
Architecture.Arm64 => "arm64",
Architecture.Wasm => "wasm",
Architecture.S390x => "s390x",
Architecture.LoongArch64 => "loongarch64",
Architecture.Armv6 => "armv6",
Architecture.Ppc64le => "ppc64le",
_ => RuntimeInformation.ProcessArchitecture.ToString(),
};

Expand Down

0 comments on commit 2a82c35

Please sign in to comment.