/// <summary> /// Copys the given processes data to this process. /// </summary> /// <param name="vm">Virtual machine this oricess us associated with.</param> /// <param name="process">Process to recieve data from.</param> public ScriptProcess(VirtualMachine vm, ScriptProcess process) { HighPreformanceTimer timer = new HighPreformanceTimer(); // Store virtual machine for layer use. _virtualMachine = vm; // Load the given script into this process. process.CopyTo(this); // Create a default thread that should run this process. ScriptThread newThread = new ScriptThread(this); // Attach console commands / exported command to this thread. // TODO: What if they already exist? foreach (Symbol symbol in _symbolList) if (symbol != null && symbol.Type == SymbolType.Function) { if (((FunctionSymbol)symbol).IsConsole == true) new ScriptConsoleCommand((FunctionSymbol)symbol, newThread); else if (((FunctionSymbol)symbol).IsExport == true) new ScriptExportFunction((FunctionSymbol)symbol, newThread); else if (((FunctionSymbol)symbol).IsImport == true) { // Find the functions parameter types. DataTypeValue[] parameterTypes = new DataTypeValue[((FunctionSymbol)symbol).ParameterCount]; for (int i = 0; i < ((FunctionSymbol)symbol).ParameterCount; i++) parameterTypes[(((FunctionSymbol)symbol).ParameterCount - 1) - i] = ((VariableSymbol)symbol.Symbols[i]).DataType; ((FunctionSymbol)symbol).NativeFunction = _virtualMachine.FindNativeFunction(symbol.Identifier, parameterTypes); } } }
/// <summary> /// Loads a new script and creates a process out of it, then associates it /// with this virtual machine. /// </summary> /// <param name="url">Url of file this script is in.</param> /// <param name="cache">If set to true this scripts byte code will be cached for quick loading.</param> public ScriptProcess LoadScript(object url, bool cache) { DebugLogger.WriteLog("Loading script into virtual machine from " + url); HighPreformanceTimer timer = new HighPreformanceTimer(); if (Resources.ResourceManager.ResourceIsCached(url.ToString())) { ScriptProcess oldProcess = (ScriptProcess)Resources.ResourceManager.RetrieveResource(url.ToString()); // Create process and hand loading over to it. ScriptProcess process = new ScriptProcess(this, (ScriptProcess)oldProcess); process.Url = url as string; _processes.Add(process); DebugLogger.WriteLog("Loaded script from cache in "+timer.DurationMillisecond+"."); return process; } // Open a stream so we can read in the script. Stream stream = StreamFactory.RequestStream(url, StreamMode.Open); if (stream == null) return null; BinaryReader reader = new BinaryReader(stream); // Check if this script is already compiled or not. if (reader.ReadByte() == 'C' && reader.ReadByte() == 'R' && reader.ReadByte() == 'X') { // Clean up our file handle. reader.Close(); stream.Close(); // Create process and hand loading over to it. ScriptProcess process = new ScriptProcess(this, url); process.Url = url as string; _processes.Add(process); if (cache == true) Resources.ResourceManager.CacheResource(url.ToString(), process); DebugLogger.WriteLog("Script loaded in " + timer.DurationMillisecond + "."); return process; } else { // Clean up our file handle. reader.Close(); // Compiler script to byte code. ScriptCompiler compiler = new ScriptCompiler(); if (compiler.Compile(url) > 0) { bool serious = false; foreach (CompileError error in compiler.ErrorList) if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError) serious = true; if (serious == true) { DebugLogger.WriteLog(compiler.ErrorList.Count + " error(s) occured while compiling script from " + url.ToString() + "."); foreach (CompileError error in compiler.ErrorList) DebugLogger.WriteLog("\t" + error.ToString()); return null; } } // Create a memory stream and dump the byte code into it. Stream memoryStream = new MemoryStream(); if (memoryStream == null) return null; BinaryWriter memoryWriter = new BinaryWriter(memoryStream); BinaryReader memoryReader = new BinaryReader(memoryStream); compiler.DumpExecutableFile(memoryWriter); // Create process and hand loading over to it. memoryStream.Position = 0; ScriptProcess process = new ScriptProcess(this, memoryReader); process.Url = url as string; _processes.Add(process); memoryReader.Close(); memoryWriter.Close(); memoryStream.Close(); stream.Close(); if (cache == true) Resources.ResourceManager.CacheResource(url.ToString(), process); DebugLogger.WriteLog("Script loaded in " + timer.DurationMillisecond + "."); return process; } }
/// <summary> /// Called by the base engine class when its safe to update and render the scene. /// </summary> protected override void Update() { // Ignore everything else if we are not running a game. if (_gameName == "") { return; } //System.Console.WriteLine("Collective Time("+EntityNode.CollectiveCalls+" calls): "+EntityNode.CollectiveTime); //EntityNode.CollectiveTime = 0.0f; //EntityNode.CollectiveCalls = 0; //EntityNode.CollectiveTimer.Restart(); // Time to load a map? if (_mapLoadPending == true) { // Pump out a MapFinish event. EventManager.FireEvent(new Event("map_finish", this, null)); // Allow the processes some time to be notified of closing events. //EventManager.ProcessEvents(); //ProcessManager.RunProcesses(1); // Tell the scripts that we are now loading the new map (so they can show a loadings screen). _gameScriptProcess.Process.InvokeFunction("OnLoadingBegin", true, true); // Don't want to render the scene graph as its currently being loaded >.<. bool priorSceneGraphRender = true; if (_isServer == false) { priorSceneGraphRender = _window.RenderSceneGraph; _window.RenderLoadingScreen = true; _window.RenderSceneGraph = false; } // Keep track of time :). HighPreformanceTimer loadTimer = new HighPreformanceTimer(); // Get starting memory. long startingMemory = GC.GetTotalMemory(true); if (GraphicsManager.ThreadSafe == false) { // Load the new map. DebugLogger.WriteLog("Loading map from " + _mapLoadFile + " " + (_mapLoadPassword != "" ? " with password " + _mapLoadPassword : "") + "."); LoadMapThread(); } else { // Load the new map. DebugLogger.WriteLog("Loading map from " + _mapLoadFile + " " + (_mapLoadPassword != "" ? " with password " + _mapLoadPassword : "") + "."); Thread thread = new Thread(LoadMapThread); thread.Priority = ThreadPriority.Highest; // Thread.CurrentThread.Priority = ThreadPriority.Lowest; thread.IsBackground = true; thread.Start(); // Ech, there has to be a better way than this. I hate thread safety >.>. HighPreformanceTimer timer = new HighPreformanceTimer(); while (thread != null && thread.IsAlive == true) { // Track frame stats. TrackFrameStatsBegin(); // Update the process. //timer = new HighPreformanceTimer(); //_gameScriptProcess.Run(_deltaTime); //_processProcessingDuration = (float)timer.DurationMillisecond; // Update the graphical console. if (_isServer == false) { GraphicalConsole.Update(1.0f); } // Tell the window to render if (_isServer == false) { timer.Restart(); GraphicsCanvas.RenderAll(); _window.Render(); _renderingDuration = (float)timer.DurationMillisecond; } // Update network. NetworkManager.Poll(); // Process application level events. timer.Restart(); Application.DoEvents(); _applicationProcessingDuration = (float)timer.DurationMillisecond; // Track frame stats. TrackFrameStatsFinish(); } } // Invoke OnCreate events of scripted entities. foreach (SceneNode node in _map.SceneGraph.EnumerateNodes()) { if (node != null && node is ScriptedEntityNode && node.IsPersistent == false) { ((ScriptedEntityNode)node).ScriptProcess[0].InvokeFunction("OnCreate", true, false); } } // Run the collision manager quickly so that we can sort out any unplesent problems. CollisionManager.ProcessCollisions(); //Thread.CurrentThread.Priority = ThreadPriority.Normal; // We can render again! Oh holy days! if (_isServer == false) { _window.RenderLoadingScreen = false; _window.RenderSceneGraph = priorSceneGraphRender; } // Remove any old resource from the cache that haven't been used for 5 maps :P. ResourceManager.CollectGarbage(3); // Free up some space. GC.Collect(); // And we are done! DebugLogger.WriteLog("Map loaded successfully in " + loadTimer.DurationMillisecond + "ms, " + (((GC.GetTotalMemory(false) - startingMemory) / 1024.0f) / 1024.0f) + "mb allocated during loading."); // Yay, loaded! _mapLoadPending = false; // Reset the delta time! _forcedDeltaTimeThisFrame = 1.0f; } }