@@ -7,16 +7,18 @@ MIT License
77using System ;
88using System . Collections . Generic ;
99using System . IO ;
10+ using System . IO . MemoryMappedFiles ;
1011using System . Linq ;
1112using System . Reflection ;
1213using Microsoft . CodeAnalysis ;
1314using Microsoft . CodeAnalysis . CSharp ;
1415using Microsoft . CodeAnalysis . Text ;
1516using MinecraftClient ;
17+ using SingleFileExtractor . Core ;
1618
1719namespace DynamicRun . Builder
1820{
19- internal class Compiler
21+ internal class Compiler
2022 {
2123 public CompileResult Compile ( string filepath , string fileName )
2224 {
@@ -58,23 +60,101 @@ private static CSharpCompilation GenerateCode(string sourceCode, string fileName
5860
5961 var parsedSyntaxTree = SyntaxFactory . ParseSyntaxTree ( codeString , options ) ;
6062
63+ var mods = Assembly . GetEntryAssembly ( ) . GetModules ( ) ;
64+
65+ #pragma warning disable IL3000
66+ // System.Private.CoreLib
67+ var A = typeof ( object ) . Assembly . Location ;
68+ // System.Console
69+ var B = typeof ( Console ) . Assembly . Location ;
70+ // The path to MinecraftClient.dll
71+ var C = typeof ( Program ) . Assembly . Location ;
72+
6173 var references = new List < MetadataReference >
6274 {
63- MetadataReference . CreateFromFile ( typeof ( object ) . Assembly . Location ) ,
64- MetadataReference . CreateFromFile ( typeof ( Console ) . Assembly . Location ) ,
65- MetadataReference . CreateFromFile ( typeof ( ChatBot ) . Assembly . Location )
75+ MetadataReference . CreateFromFile ( A ) ,
76+ MetadataReference . CreateFromFile ( B )
6677 } ;
67-
68- Assembly . GetEntryAssembly ( ) ? . GetReferencedAssemblies ( ) . ToList ( )
69- . ForEach ( a => references . Add ( MetadataReference . CreateFromFile ( Assembly . Load ( a ) . Location ) ) ) ;
7078
79+ // We're on a Single File Application, so we need to extract the executable to get the assembly.
80+ if ( string . IsNullOrEmpty ( C ) )
81+ {
82+ // Create a temporary file to copy the executable to.
83+ var executableDir = System . AppContext . BaseDirectory ;
84+ var executablePath = Path . Combine ( executableDir , "MinecraftClient.exe" ) ;
85+ var tempFileName = Path . GetTempFileName ( ) ;
86+ if ( File . Exists ( executablePath ) )
87+ {
88+ // Copy the executable to a temporary path.
89+ ExecutableReader e = new ( ) ;
90+ File . Delete ( tempFileName ) ;
91+ File . Copy ( executablePath , tempFileName ) ;
92+
93+ // Access the contents of the executable.
94+ var viewAccessor = MemoryMappedFile . CreateFromFile ( tempFileName , FileMode . Open ) . CreateViewAccessor ( ) ;
95+ var manifest = e . ReadManifest ( viewAccessor ) ;
96+ var files = manifest . Files ;
97+
98+ Stream ? assemblyStream ;
99+
100+ var assemblyrefs = Assembly . GetEntryAssembly ( ) ? . GetReferencedAssemblies ( ) . ToList ( ) ;
101+ assemblyrefs . Add ( new ( "MinecraftClient" ) ) ;
102+
103+ foreach ( var refs in assemblyrefs ) {
104+ var loadedAssembly = Assembly . Load ( refs ) ;
105+ if ( string . IsNullOrEmpty ( loadedAssembly . Location ) )
106+ {
107+ // Check if we can access the file from the executable.
108+ var reference = files . FirstOrDefault ( x => x . RelativePath . Remove ( x . RelativePath . Length - 4 ) == refs . Name ) ;
109+ var refCount = files . Count ( x => x . RelativePath . Remove ( x . RelativePath . Length - 4 ) == refs . Name ) ;
110+ if ( refCount > 1 )
111+ {
112+ // Safety net for the case where the assembly is referenced multiple times.
113+ // Should not happen normally, but we can make exceptions when it does happen.
114+ throw new InvalidOperationException ( "Too many references to the same assembly. Assembly name: " + refs . Name ) ;
115+ }
116+ if ( reference == null )
117+ {
118+ throw new InvalidOperationException ( "The executable does not contain a referenced assembly. Assembly name: " + refs . Name ) ;
119+ }
120+
121+ assemblyStream = GetStreamForFileEntry ( viewAccessor , reference ) ;
122+ references . Add ( MetadataReference . CreateFromStream ( assemblyStream ) ) ;
123+ continue ;
124+ }
125+ references . Add ( MetadataReference . CreateFromFile ( loadedAssembly . Location ) ) ;
126+ }
127+
128+ // Cleanup.
129+ viewAccessor . Flush ( ) ;
130+ viewAccessor . Dispose ( ) ;
131+ }
132+ }
133+ else
134+ {
135+ references . Add ( MetadataReference . CreateFromFile ( C ) ) ;
136+ Assembly . GetEntryAssembly ( ) ? . GetReferencedAssemblies ( ) . ToList ( ) . ForEach ( a => references . Add ( MetadataReference . CreateFromFile ( Assembly . Load ( a ) . Location ) ) ) ;
137+ }
138+ #pragma warning restore IL3000
71139 return CSharpCompilation . Create ( $ "{ fileName } .dll",
72- new [ ] { parsedSyntaxTree } ,
140+ new [ ] { parsedSyntaxTree } ,
73141 references : references ,
74142 options : new CSharpCompilationOptions ( OutputKind . DynamicallyLinkedLibrary ,
75143 optimizationLevel : OptimizationLevel . Release ,
76144 assemblyIdentityComparer : DesktopAssemblyIdentityComparer . Default ) ) ;
77145 }
146+
147+ private static Stream ? GetStreamForFileEntry ( MemoryMappedViewAccessor viewAccessor , FileEntry file )
148+ {
149+ var stream = typeof ( BundleExtractor ) . GetMethod ( "GetStreamForFileEntry" , BindingFlags . NonPublic | BindingFlags . Static ) ! . Invoke ( null , new object [ ] { viewAccessor , file } ) as Stream ;
150+
151+ if ( stream == null )
152+ {
153+ throw new InvalidOperationException ( "The executable does not contain the assembly. Assembly name: " + file . RelativePath ) ;
154+ }
155+
156+ return stream ;
157+ }
78158
79159 internal struct CompileResult {
80160 internal byte [ ] ? Assembly ;
0 commit comments