/// <summary> /// Initializes a new instance of this class with the given data. /// </summary> /// <param name="entity">Entity to attach this process to.</param> /// <param name="process">Script process that this entitys logic script is contained in.</param> public ScriptExecutionProcess(EntityNode entity, ScriptProcess process) { _entity = entity; Process = process; _eventListener = new EventListener(ProcessEvent); EventManager.AttachListener(_eventListener); _priority = 1; // We always want to be executed before other processes. }
/// <summary> /// Called when the state of this entities script is changed. /// </summary> /// <param name="process">Process that had its state changed.</param> /// <param name="sate">New state.</param> public void OnStateChange(ScriptProcess process, StateSymbol state) { _renderFunction = state == null ? null : _process.Process.State.FindSymbol("OnRender", SymbolType.Function) as FunctionSymbol; // SyncCollisionEvents(); }
/// <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> /// Removes a previously attached process from this VM. /// </summary> /// <param name="process">Process to remove.</param> public void DetachProcess(ScriptProcess process) { _processes.Remove(process); }
/// <summary> /// Attachs a process to this VM. /// </summary> /// <param name="process">Process to attach.</param> public void AttachProcess(ScriptProcess process) { _processes.Add(process); }
private RuntimeStack _runtimeStack = new RuntimeStack(512); // When the hell are you going to use more than 512? #endregion Fields #region Constructors /// <summary> /// Initializes a new instance of this class: and associates it with /// the given script process. /// </summary> /// <param name="process">Script process that this thread is associated with.</param> public ScriptThread(ScriptProcess process) { _process = process; _process.AttachThread(this); InvokeFunction("$global", true, true, true); }
/// <summary> /// Copys this processes data to another process. /// </summary> /// <param name="process">Process to copy to.</param> public void CopyTo(ScriptProcess process) { process._defineList = _defineList; process._internalVariableIndex = _internalVariableIndex; process._memorySize = _memorySize; process._globalScope = _globalScope; process._memberScope = _memberScope; process._symbolList = _symbolList; process._instructionList = _instructionList; //process._memoryHeap = new RuntimeObject[_memoryHeap.Length]; //process._objectHeap = new RuntimeObject[_objectHeap.Length]; //process._currentState = _currentState; process._defaultEditorStateIndex = _defaultEditorStateIndex; process._defaultEngineStateIndex = _defaultEngineStateIndex; process._url = _url; process._memberFunctionHashTable = _memberFunctionHashTable; // Create a new memory heap of the correct size for (int i = 0; i < _memorySize; i++) process._memoryHeap[i] = new RuntimeValue(RuntimeValueType.Invalid); // Set the 'special' globals to their appropriate values. //process._memoryHeap[0].ValueType = RuntimeValueType.Object; //process._memoryHeap[0].ObjectIndex = -1; }
/// <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> /// Called when the state of this entities script is changed. /// </summary> /// <param name="process">Process that had its state changed.</param> /// <param name="sate">New state.</param> public void OnStateChange(ScriptProcess process, StateSymbol state) { _tickFunction = (state == null ? null : (state.FindSymbol("OnTick", SymbolType.Function) as FunctionSymbol)); }
/// <summary> /// Called when this process needs to be destroyed. /// </summary> public override void Dispose() { if (_eventListener != null) EventManager.DetachListener(_eventListener); if (_process != null) _process.Dispose(); _eventListener = null; _process = null; _entity = null; }
/// <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> /// Called when the state of this entities script is changed. /// </summary> /// <param name="process">Process that had its state changed.</param> /// <param name="sate">New state.</param> public void OnStateChange(ScriptProcess process, StateSymbol state) { if (_isServer == true) return; if (_mapScriptProcess != null && process == _mapScriptProcess.Process) _window.MapScriptRenderFunction = state.FindSymbol("OnRender", SymbolType.Function) as FunctionSymbol; else if (_gameScriptProcess != null && process == _gameScriptProcess.Process) _window.GameScriptRenderFunction = state.FindSymbol("OnRender", SymbolType.Function) as FunctionSymbol; }