RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Script Compiler to only recompile when changes are made

UOT

Knight
Script Compiler to only recompile when changes are made

Even though this isn't really necessary since through out my tests it only takes around 10 seconds to compile the scripts anyway I thought I'd share this. This modification to Compile will check for newer or altered scripts (both .cs and .vb) throughout your scripts folder and cache the script file names to 2 files ScriptCountCS.cnt and ScriptCountVB.cnt to make a quicker comparison for the sebsequent loads. If it finds a Scripts.CS.dll or Scripts.VB.dll in your Scripts\Output \ folder it will first check to see if your script folder has any scripts (for shards that don't want to upload their scripts), if it does have scripts, it will check for newer files and it will load the compiled DLLs if no newer files are found. You can see the timing when you run the server in -debug mode. Even though I used plenty of exception handling and feel this code is safe: USE AT YOUR OWN RISK

Just replace the whole compile (bool debug) function
Code:
public static bool Compile( bool debug )
with the following code.
PHP:
		private static bool CacheScriptNames(string type, bool debug)
		{
			string[] files = GetScripts( type );
			return CacheScriptNames( type, files, debug );
		}
		
		private static bool CacheScriptNames(string type, string[] files, bool debug)
		{
			DateTime dt = DateTime.Now;
			TimeSpan dt1 = new TimeSpan();
			
			if (File.Exists( string.Format("ScriptCount{0}.cnt", type == "*.vb" ? "VB" : "CS" )))
			{
				int size;
				string[] CachedScripts;
				FileStream fs = null;
				BinaryReader r = null;
				
				try
				{
					fs = new FileStream( string.Format("ScriptCount{0}.cnt", type == "*.vb" ? "VB" : "CS" ),FileMode.Open, FileAccess.Read  );
					r = new BinaryReader(fs);
					size = r.ReadInt32();
					CachedScripts = new string[size];
					for (int i=0;i < size;i++)
					{
						CachedScripts[i] = r.ReadString();
					}
					r.Close();
					fs.Close();
					if (debug)
						Console.WriteLine("You have {0} {1} script files cached.", size.ToString(), type == "*.vb" ? "VB.NET" : "C#" );
				}
				catch
				{
					if (r != null)
						r.Close();
					if (fs != null)
						fs.Close();
					
					Console.WriteLine("Error loading script cache...Recreating cache files...Recompiling scripts...");
					try
					{
						fs = new FileStream(string.Format("ScriptCount{0}.cnt", type == "*.vb" ? "VB" : "CS" ), FileMode.Create  );
						BinaryWriter w = new BinaryWriter(fs);
						w.Flush();
						w.Write( (int) files.Length );
						for (int i=0;i < files.Length;i++)
						{
							w.Write(files[i]);
						}
						w.Close();
						fs.Close();
					}
					catch (Exception err)
					{
						Console.WriteLine( "An error occured caching files. Error: {0}", err.Message );
						return false;
					}
					return false;
				}
				if (size != files.Length)
				{
					try
					{
						fs = new FileStream(string.Format("ScriptCount{0}.cnt", type == "*.vb" ? "VB" : "CS" ), FileMode.Create  );
						BinaryWriter w = new BinaryWriter(fs);
						w.Flush();
						w.Write( (int) files.Length );
						for (int i=0;i < files.Length;i++)
						{
							w.Write(files[i]);
						}
						w.Close();
						fs.Close();
						if (debug)
						{
							Console.WriteLine("You now have {0} scripts and previously had {1} scripts.", type == "*.vb" ? "VB" : "CS" ,files.Length.ToString(), size.ToString());
							dt1 = DateTime.Now - dt;
							Console.WriteLine("Verified {0} scripts in {1}m{2}s.{3}ms.", dt1.Minutes , dt1.Seconds , dt1.Milliseconds );
						}
					}
					catch (Exception err)
					{
						Console.WriteLine( "An error occured caching files. Error: {0}", err.Message );
						return false;
					}
					return false;
				}
				else
				{
					bool Found = false;
					for ( int i=0; i < files.Length; i++ )
					{
						for (int j=0; j < CachedScripts.Length; j++ )
						{
							if (CachedScripts[j] == files[i])
							{
								Found = true;
								break;
							}
						}
						if (Found)
							Found = false;
						else
						{
							if (debug)
							{
								dt1 = DateTime.Now - dt;
								Console.WriteLine("Verified scripts in {0}m{1}s.{2}ms.", dt1.Minutes , dt1.Seconds , dt1.Milliseconds );
							}
							return false;
						}
					}
				}
				return true;
			}
			else
			{
				try
				{
					FileStream fs = new FileStream(string.Format("ScriptCount{0}.cnt", type == "*.vb" ? "VB" : "CS" ), FileMode.Create );
					BinaryWriter w = new BinaryWriter(fs);
					w.Flush();
					w.Write( (int) files.Length );
					for (int i=0;i < files.Length;i++)
					{
						w.Write(files[i]);
					}
					w.Close();
					fs.Close();
					if (debug)
					{
						dt1 = DateTime.Now - dt;
						Console.WriteLine("Verified scripts in {0}m{1}s.{2}ms.", dt1.Minutes , dt1.Seconds , dt1.Milliseconds );
					}
				}
				catch  ( Exception err )
				{
					Console.WriteLine( "An Error Occurred. Skipping to Recompile... Error: {0}", err.ToString() );
				}
				return false;
			}
			return true;
		}
		
		private static DateTime GetNewest(string type, bool debug)
		{
			DateTime LastModScript = DateTime.MinValue;
			DateTime dt = DateTime.Now;
			TimeSpan dt1 = new TimeSpan();
			
			string[] files = GetScripts( type );
			
			if (CacheScriptNames(type, files, debug))
			{
				for (int i = 0;i<files.Length;i++)
				{
					if (LastModScript < File.GetCreationTime (files[i]))
						LastModScript = File.GetCreationTime (files[i]);
					if(LastModScript < File.GetLastWriteTime (files[i]))
						LastModScript = File.GetLastWriteTime(files[i]);
				}
				if (debug)
				{
					dt1 = DateTime.Now - dt;
					Console.WriteLine("Verified scripts in {0}m{1}s.{2}ms.", dt1.Minutes , dt1.Seconds , dt1.Milliseconds );
				}
				return LastModScript;
			}
			if (debug)
			{
				dt1 = DateTime.Now - dt;
				Console.WriteLine("Verified scripts in {0}m{1}s.{2}ms.", dt1.Minutes , dt1.Seconds , dt1.Milliseconds );
			}
			return DateTime.Now;
		}
		
		private static bool LoadScriptDLL(string path, string type, out Assembly scripts, bool debug)
		{
			scripts = null;
			try
			{
				scripts = Assembly.LoadFile( path );
				return true;
			}
			catch ( Exception err )
			{
				Console.WriteLine( "Unable to load Scripts.{0}.dll. Compiling scripts now.. Error: {1}", type == "*.vb" ? "VB" : "CS" , err.ToString() );
				return false;
			}
			return false;
		}
		
		public static void CleanDir(string path, bool debug)
		{
			DirectoryInfo di = new DirectoryInfo(path);
			FileInfo[] fi = di.GetFiles();
			for ( int i=0; i < fi.Length; i++ )
			{
				if (debug)
					Console.Write( "Trying to delete {0}", fi[i].Name );
				try
				{
					fi[i].Delete();
					if (debug)
						Console.WriteLine("...Deleted");
				}
				catch (Exception err)
				{
					if (debug)
						Console.WriteLine("...Failed! Error: {0}", err.Message );
				}
			}
		}
		
		public static bool Compile( bool debug )
		{
			EnsureDirectory( "Scripts/" );
			EnsureDirectory( "Scripts/Output/" );
			
			DateTime dt = DateTime.Now;
			DateTime ScriptsDLL = DateTime.MinValue;
			DateTime LastModScript = DateTime.MinValue;
			
			string cspath = Path.Combine( Core.BaseDirectory, @"Scripts\Output\Scripts.CS.dll" );
			string vbpath = Path.Combine( Core.BaseDirectory, @"Scripts\Output\Scripts.VB.dll" );
			bool LoadDLL = false;
			bool Recompile = false;
			bool FoundDLL = false;
			int a = 0;
			Assembly vbscripts = null;
			Assembly csscripts = null;
			
			if ( File.Exists(cspath) )
			{
				FoundDLL = true;
				ScriptsDLL = File.GetLastWriteTime(cspath);
				if (debug)
					Console.WriteLine("Checking for C# scripts modified after {0}....", ScriptsDLL);
				
				LastModScript = GetNewest("*.cs",debug);
				if ( LastModScript < ScriptsDLL)
					LoadDLL = true;
				else
					LoadDLL = false;
			}
			
			if ( File.Exists(vbpath) && LoadDLL )
			{
				ScriptsDLL = File.GetLastWriteTime(vbpath);
				if (debug)
					Console.WriteLine("Checking for VB.NET scripts modified after {0}....", ScriptsDLL);
				
				LastModScript = GetNewest("*.vb",debug);
				if ( LastModScript < ScriptsDLL)
					LoadDLL = true;
				else
					LoadDLL = false;
			}
			else if ( (GetScripts( "*.vb" )).Length > 0 )
			{
				CacheScriptNames("*.vb", debug);
				LoadDLL = false;
			}
			
			if ( LoadDLL || ( FoundDLL && (GetScripts( "*.cs" )).Length < 1 && (GetScripts( "*.vb" )).Length < 1) )
			{
				if (debug)
					Console.WriteLine("Loading C# scripts .dll");
				LoadDLL = LoadScriptDLL(cspath,"*.cs",out csscripts, debug);
				if ( File.Exists(vbpath) )
				{
					if (debug)
						Console.WriteLine("Loading VB.NET scripts .dll");
					LoadDLL = LoadScriptDLL(vbpath,"*.vb",out vbscripts, debug);
				}
				if ( csscripts == null || vbscripts == null )
					m_Assemblies = new Assembly[1];
				else
					m_Assemblies = new Assembly[2];
				if ( csscripts != null )
					m_Assemblies[a++] = csscripts;
				
				if ( vbscripts != null )
					m_Assemblies[a++] = vbscripts;
				a = 0;
				if (debug)
					Console.WriteLine("No scripts modified after last compile or no scripts found. Loading pre-compiled scripts...");
			}
			
			if (!LoadDLL)
			{
				if (debug)
					Console.WriteLine("Unable to load script library. Compiling...");
				CompilerResults csResults = null, vbResults = null;
				
				if ( vbscripts != null )
					
					csscripts = null;
				CleanDir(Path.Combine( Core.BaseDirectory, @"Scripts\Output"), debug);
				
				if ( m_AdditionalReferences.Count > 0 )
					m_AdditionalReferences.Clear();
				
				csResults = CompileCSScripts( debug );
				
				if ( csResults == null || !csResults.Errors.HasErrors )
					vbResults = CompileVBScripts( debug );
				
				if ( ( csResults == null || !csResults.Errors.HasErrors ) && ( vbResults == null || !vbResults.Errors.HasErrors ) && ( vbResults != null || csResults != null ) )
				{
					if ( csResults == null || vbResults == null )
						m_Assemblies = new Assembly[1];
					else
						m_Assemblies = new Assembly[2];
					
					if ( csResults != null )
						m_Assemblies[a++] = csResults.CompiledAssembly;
					
					if ( vbResults != null )
						m_Assemblies[a++] = vbResults.CompiledAssembly;
					Recompile=true;
				}
				else
					Recompile=false;
			}
			if (LoadDLL || Recompile)
			{
				if (debug)
				{
					TimeSpan dt1 = DateTime.Now - dt;
					Console.WriteLine("Loaded in {0}m{1}s.{2}ms.", dt1.Minutes , dt1.Seconds , dt1.Milliseconds );
				}
				Console.Write( "Scripts: Verifying..." );
				Core.VerifySerialization();
				Console.WriteLine( "done ({0} items, {1} mobiles)", Core.ScriptItems, Core.ScriptMobiles );
				
				ArrayList invoke = new ArrayList();
				try
				{
					for (a=0;a<m_Assemblies.Length;++a)
					{
						Type[] types = m_Assemblies[a].GetTypes();
						
						for ( int i = 0; i < types.Length; ++i )
						{
							MethodInfo m = types[i].GetMethod( "Configure", BindingFlags.Static | BindingFlags.Public );
							
							if ( m != null )
								invoke.Add( m );
							//m.Invoke( null, null );
						}
					}
					
					invoke.Sort( new CallPriorityComparer() );
					
					for ( int i = 0; i < invoke.Count; ++i )
						((MethodInfo)invoke[i]).Invoke( null, null );
					
					invoke.Clear();
				}
				catch
				{
					return false;
				}
				World.Load();
				
				for (a=0;a<m_Assemblies.Length;++a)
				{
					Type[] types = m_Assemblies[a].GetTypes();
					
					for ( int i = 0; i < types.Length; ++i )
					{
						MethodInfo m = types[i].GetMethod( "Initialize", BindingFlags.Static | BindingFlags.Public );
						
						if ( m != null )
							invoke.Add( m );
						//m.Invoke( null, null );
					}
				}
				
				invoke.Sort( new CallPriorityComparer() );
				
				for ( int i = 0; i < invoke.Count; ++i )
					((MethodInfo)invoke[i]).Invoke( null, null );
				return true;
			}
			else
			{
				return false;
			}
		}
For those who haven't made any mods to your ScriptCompiler.cs script and don't feel like copy and pasting I've attached the ScriptCompiler.cs file so your can just replace the original.
 

Attachments

  • ScriptCompiler.cs
    21 KB · Views: 103
Top