/// <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 asset manager whenever a script is modified. /// </summary> /// <param name="sender">The script window that invoked this event.</param> /// <param name="e">Arguments explaining why this event occured.</param> private void ScriptModified(object sender, EventArgs e) { ScriptEditorWindow editorWindow = sender as ScriptEditorWindow; // Compile the script. ScriptCompiler compiler = new ScriptCompiler(); bool errorOccured = false; string errorDescription = ""; if (compiler.Compile(editorWindow.Url) > 0) foreach (CompileError error in compiler.ErrorList) if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError) { errorDescription += (errorDescription == "" ? "" : "\n") + error.ToString(); errorOccured = true; } // If an error occured notify the user if not then // insert a new scripted entity into the map. if (errorOccured == true) { MessageBox.Show("Unable to recompile object's script, the following error(s) occured while attempt to compile object's script.\n\n" + errorDescription, "Compile Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); DebugLogger.WriteLog("Object's script recompile aborted. The following error(s) occured while attempting to compile object's script.\n\n" + errorDescription, LogAlertLevel.Warning); return; } foreach (SceneNode node in Engine.Engine.GlobalInstance.Map.SceneGraph.EnumerateNodes()) { if (node is ScriptedEntityNode == false) continue; ScriptedEntityNode scriptEntityNode = node as ScriptedEntityNode; if (scriptEntityNode.ScriptProcess.Url.ToLower() != ((string)editorWindow.Url).ToLower()) continue; // Dump the compiled code into a memory stream. MemoryStream memStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(memStream); BinaryReader reader = new BinaryReader(memStream); compiler.DumpExecutableFile(writer); memStream.Position = 0; // Store current values of properties so we can set them in the // new script later. Hashtable propertyValueTable = new Hashtable(); foreach (Symbol symbol in scriptEntityNode.ScriptProcess.GlobalScope.Symbols) { if (symbol is VariableSymbol == false || ((VariableSymbol)symbol).IsProperty == false) continue; VariableSymbol propertySymbol = symbol as VariableSymbol; propertyValueTable.Add(propertySymbol.Identifier, propertySymbol); } // Create a new scripted entity with the given script attached to it. ScriptProcess previousScript = scriptEntityNode.ScriptProcess; scriptEntityNode.ScriptProcess = new ScriptProcess(null, reader); scriptEntityNode.ScriptProcess.Url = previousScript.Url; // Free up the streams. memStream.Close(); reader.Close(); writer.Close(); // Go through each property in this process and set its value to // the old one (if it exists). foreach (Symbol symbol in scriptEntityNode.ScriptProcess.GlobalScope.Symbols) { if (symbol is VariableSymbol == false || ((VariableSymbol)symbol).IsProperty == false) continue; VariableSymbol propertySymbol = symbol as VariableSymbol; if (propertyValueTable.Contains(propertySymbol.Identifier) == true) { VariableSymbol previousPropertySymbol = (VariableSymbol)propertyValueTable[propertySymbol.Identifier]; if (previousPropertySymbol.DataType != propertySymbol.DataType) continue; switch (propertySymbol.DataType.DataType) { case DataType.Bool: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetBooleanGlobal(propertySymbol.Identifier)); break; case DataType.Byte: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetByteGlobal(propertySymbol.Identifier)); break; case DataType.Double: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetDoubleGlobal(propertySymbol.Identifier)); break; case DataType.Float: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetFloatGlobal(propertySymbol.Identifier)); break; case DataType.Int: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetIntegerGlobal(propertySymbol.Identifier)); break; case DataType.Long: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetLongGlobal(propertySymbol.Identifier)); break; case DataType.Short: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetShortGlobal(propertySymbol.Identifier)); break; case DataType.String: scriptEntityNode.ScriptProcess[0].SetGlobalVariable(propertySymbol.Identifier, previousScript[0].GetStringGlobal(propertySymbol.Identifier)); break; } } } if (_entityPropertiesWindow != null && _entityPropertiesWindow.Entity == node) _entityPropertiesWindow.SyncronizeData(); } }
/// <summary> /// Copys a directory tree from one location to another, unlike the one in IOMethods this /// one will also increment a progress bar as it copys the directory tree. /// </summary> /// <param name="from">The source directory tree.</param> /// <param name="to">The destination path of the directory tree.</param> private void CopyDirectoryWithProgress(string from, string to) { // Append a directory seperator to the end of the path. if (to[to.Length - 1] != Path.DirectorySeparatorChar) to += Path.DirectorySeparatorChar; // If the destination directory does not exist then create it. if (Directory.Exists(to) == false) Directory.CreateDirectory(to); // Retrieve all the files in the directory to be copied. string[] files = Directory.GetFileSystemEntries(from); // Update the progress bar. DebugLogger.WriteLog("Copying directory \"" + from + "\"..."); _subTaskProgress = 0; _subTask = "Copying directory: " + from; _logStack.Push(_subTask); // Go through each sub directory and file and copy it. int index = 1; foreach (string file in files) { if (Directory.Exists(file) == true) CopyDirectoryWithProgress(file, to + Path.GetFileName(file)); else { _logStack.Push("Copying file \"" + file + "\"..."); // Check if its a script file which would mean we have to compile it. if (file.ToLower().EndsWith(".fs") == true || file.ToLower().EndsWith(".fso") == true) { // See if we should compile it or not. if (_compileScripts == true) { // Create a compile and compile the script. ScriptCompiler compiler = new ScriptCompiler(); _logStack.Push("Compiling script \"" + file + "\"..."); // If there are any errors when compiling the script yell // at the user. string errorMessage = ""; bool showErrorMessage = false; if (compiler.Compile(file, _compileFlags, _scriptDefineList, _scriptIncludePathList) > 0) { errorMessage = compiler.ErrorList.Count + " errors occured while compiling the script \""+file+"\" \n\n"; foreach (CompileError error in compiler.ErrorList) { if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError || (error.AlertLevel == ErrorAlertLevel.Warning && _treatWarningsAsErrors == true) || (error.AlertLevel == ErrorAlertLevel.Message && _treatMessagesAsErrors == true) ) showErrorMessage = true; errorMessage += error.ToString() + "\n"; } } if (showErrorMessage == true) { DebugLogger.WriteLog(errorMessage, LogAlertLevel.Error); _logStack.Push(errorMessage); } // Dump the compiled byte code to the build directory. if (showErrorMessage == false) compiler.DumpExecutableFile(to + Path.GetFileName(file)); } // Copy the source code if we have been told to keep it. if (_keepScriptSource == true) File.Copy(file, to + Path.GetFileName(file), true); } // Check if its a script script file. else if (file.ToLower().EndsWith(".fsl") == true) { if (_keepScriptSource == true) File.Copy(file, to + Path.GetFileName(file), true); } // Its a normal file so we can just ignore it. else File.Copy(file, to + Path.GetFileName(file), true); } _subTaskProgress = (int)(((float)index / (float)files.Length) * 100.0f); _subTask = "Copying directory: " + from; } }
/// <summary> /// Inserts the current object into the map at the cursors position (or center-screen - /// - if this is not the active window) at the highest level on the scene graph /// </summary> private void InsertCurrentObject(bool inCenter, string overrideObjectURL) { string objectURL = overrideObjectURL != "" ? overrideObjectURL : _assetManagerWindow.SelectedObjectURL; EntityNode entity = null; // Keep a log of this insertion. DebugLogger.WriteLog("Inserting object of type '" + objectURL + "' into map"); // Check the extension to see if this is a built-in object or not. if (objectURL.IndexOf(".fso") >= 0) { // Compile the script. ScriptCompiler compiler = new ScriptCompiler(); bool errorOccured = false; string errorDescription = "\t"; if (compiler.Compile(objectURL) > 0) foreach (CompileError error in compiler.ErrorList) if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError) { errorDescription += (errorDescription == "" ? "" : "\n\t") + error.ToString(); errorOccured = true; } // If an error occured notify the user if not then // insert a new scripted entity into the map. if (errorOccured == true) { MessageBox.Show("Unable to insert object into map, the following error(s) occured while attempt to compile this objects script.\n\n"+errorDescription,"Compile Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); DebugLogger.WriteLog("Object insertion aborted. The following error(s) occured while attempting to compile this objects script.\n\n" + errorDescription, LogAlertLevel.Warning); } else { // Dump the compiled code into a memory stream. MemoryStream memStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(memStream); BinaryReader reader = new BinaryReader(memStream); compiler.DumpExecutableFile(writer); memStream.Position = 0; // Create a new scripted entity with the given script attached to it. ScriptedEntityNode scriptedEntity = new ScriptedEntityNode(); entity = scriptedEntity; entity.RenderMode = EntityRenderMode.Rectangle; entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; entity.Name = Path.GetFileNameWithoutExtension(objectURL); ScriptProcess process = new ScriptProcess(VirtualMachine.GlobalInstance, reader); process.Url = objectURL; if (process.DefaultEditorState != null) process.ChangeState(process.DefaultEditorState.Identifier); else process.State = null; scriptedEntity.ScriptProcess = process; // Are we allowed to place the entity? bool canPlace = true; string placeError = "This entity has been flagged as unplaceable. Please choose another or check this objects script."; foreach (Define define in process.Defines) { switch (define.Ident.ToUpper()) { case "UNPLACEABLE": canPlace = false; break; case "UNPLACEABLE_ERROR": placeError = define.Value; break; } } if (canPlace == false) { MessageBox.Show(placeError, "Unplaceable", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); // Invoke OnCreate event. scriptedEntity.ScriptProcess[0].InvokeFunction("OnCreate", true, false); // Free up the streams. memStream.Close(); reader.Close(); writer.Close(); } } // Its built in so create the object requested. else { switch (objectURL.ToLower()) { case "tilemap segment": TilemapSegmentNode segment = new TilemapSegmentNode(8, 8, 16, 16); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(segment); segment.IsGridVisible = true; entity = segment; break; case "emitter": entity = new EmitterNode(); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; break; case "entity": entity = new EntityNode(); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; break; case "path marker": entity = new PathMarkerNode(); Engine.Engine.GlobalInstance.Map.SceneGraph.RootNode.AddChild(entity); entity.BoundingRectangle = new Rectangle(0, 0, 16, 16); entity.Width = 16; entity.Height = 16; entity.Image = _pathMarkerImage; entity.RenderMode = EntityRenderMode.Image; entity.Name = "Path Marker " + MathMethods.Random(MathMethods.Random(0, 10000), MathMethods.Random(10000, 10000000)); foreach (EntityNode selEntity in _selectedEntityList) if (selEntity is PathMarkerNode && ((PathMarkerNode)selEntity).NextNodeName == "") { ((PathMarkerNode)selEntity).NextNode = (PathMarkerNode)entity; ((PathMarkerNode)selEntity).NextNodeName = entity.Name; } break; } } if (entity == null) return; // Find the correct position for our new entity. int mapX, mapY; if (inCenter == false) { mapX = (int)Editor.GlobalInstance.CameraNode.Transformation.X + (int)((mousePositionBeforeRightClick[0] / Editor.GlobalInstance.CameraNode.Zoom)); mapY = (int)Editor.GlobalInstance.CameraNode.Transformation.Y + (int)((mousePositionBeforeRightClick[1] / Editor.GlobalInstance.CameraNode.Zoom)); } else { mapX = (int)Editor.GlobalInstance.CameraNode.Transformation.X + (int)(((mapPanel.ClientSize.Width - entity.BoundingRectangle.Width) / 2) / Editor.GlobalInstance.CameraNode.Zoom); mapY = (int)Editor.GlobalInstance.CameraNode.Transformation.Y + (int)(((mapPanel.ClientSize.Height - entity.BoundingRectangle.Height) / 2) / Editor.GlobalInstance.CameraNode.Zoom); } if (_snapToGrid == true) { mapX = (mapX / _gridWidth) * _gridWidth; mapY = (mapY / _gridHeight) * _gridHeight; } entity.Position(mapX, mapY, 0.0f); entity.IsBoundingBoxVisible = _viewBoundingBoxs; entity.IsEventLinesVisible = _viewEventLines; entity.IsCollisionBoxVisible = _viewCollisionBoxs; entity.ForceVisibility = true; ClearSelection(); AddEntityToSelection(entity); // Update the scene graph window if it exists. if (_sceneGraphWindow != null) _sceneGraphWindow.SyncronizeData(); // Update this entitys event nodes and the event nodes of others. foreach (SceneNode node in Engine.Engine.GlobalInstance.Map.SceneGraph.EnumerateNodes()) { EntityNode subNode = node as EntityNode; if (subNode == null) continue; if (subNode.Event.ToLower() == entity.Name.ToString().ToLower()) subNode.EventNodes.Add(entity); } PushUndoOperation(new InsertNodesUndoOperation(new SceneNode[] { entity })); SyncronizeWindow(); _mapChangedSinceSave = true; }
/// <summary> /// Compiles the given directory to the current pak file. /// </summary> /// <param name="from">Directory to compile.</param> private void CompileDirectoryToPak(string from) { // Retrieve all the files in the directory to be copied. string[] files = Directory.GetFileSystemEntries(from); if (from != Directory.GetCurrentDirectory() && from.ToLower().StartsWith(Directory.GetCurrentDirectory().ToLower())) from = from.Substring(Directory.GetCurrentDirectory().Length + 1); // Update the progress bar. _subTaskProgress = 0; _subTask = "Paking directory: " + from; _logStack.Push(_subTask); DebugLogger.WriteLog("Paking directory \"" + from + "\"..."); // Go through each sub directory and file and copy it. int index = 1; foreach (string subFile in files) { string file = subFile; if (file.ToLower().StartsWith(Directory.GetCurrentDirectory().ToLower())) file = file.Substring(Directory.GetCurrentDirectory().Length + 1); if (Directory.Exists(file) == true) CompileDirectoryToPak(file); else { DebugLogger.WriteLog("Paking file \"" + file + "\"..."); _logStack.Push("Paking file \"" + file + "\"..."); // Check if its a script file which would mean we have to compile it. if (file.ToLower().EndsWith(".fso") == true || file.ToLower().EndsWith(".fs") == true) { // See if we should compile it or not. if (_compileScripts == true) { // Create a compile and compile the script. ScriptCompiler compiler = new ScriptCompiler(); DebugLogger.WriteLog("Compiling script \"" + file + "\"..."); _logStack.Push("Compiling script \"" + file + "\"..."); // If there are any errors when compiling the script yell // at the user. string errorMessage = ""; bool showErrorMessage = false; if (compiler.Compile(file, _compileFlags, _scriptDefineList, _scriptIncludePathList) > 0) { errorMessage = compiler.ErrorList.Count + " errors occured while compiling the script \"" + file + "\" \n\n"; foreach (CompileError error in compiler.ErrorList) { if (error.AlertLevel == ErrorAlertLevel.Error || error.AlertLevel == ErrorAlertLevel.FatalError || (error.AlertLevel == ErrorAlertLevel.Warning && _treatWarningsAsErrors == true) || (error.AlertLevel == ErrorAlertLevel.Message && _treatMessagesAsErrors == true) ) showErrorMessage = true; errorMessage += error.ToString() + "\n"; } } if (showErrorMessage == true) { DebugLogger.WriteLog(errorMessage, LogAlertLevel.Error); _logStack.Push(errorMessage); } // Dump the compiled byte code to a temporary folder and set its path // as this files path. if (showErrorMessage == false) { string tempFile = Path.GetTempFileName(); compiler.DumpExecutableFile(tempFile); PakFile(tempFile, file); } // Copy the source code if we have been told to keep it. if (_keepScriptSource == true) PakFile(file, file + ".source"); } else { PakFile(file, file); } } // Check if its a library script file. else if (file.ToLower().EndsWith(".fsl") == true) { if (_keepScriptSource == true) PakFile(file, file); } // Its a normal file so pak it normally. else PakFile(file, file); } _subTaskProgress = (int)((100.0f / (float)files.Length) * index); _subTask = "Compiling directory: " + from; } }