Advertisement

Feature Request

Started by May 12, 2005 12:59 AM
10 comments, last by WitchLord 19 years, 6 months ago
I know you are busy with your current plans for the angelscript but i would like to request a method for allowing a script based event driven programming model. It's probably really hard to do, but it beats queueing events and polling them. Unless I am missing something already available in the library, I am not seeing how to do this only in script. As you may recall the limitations of my project require a unique method of dealing with some things that would generally be relatively simple and intuitive in standard projects. GUI callbacks, Asynchronous network events etc are examples of some of these problems. Currently to my best knowledge my only option is to create an event queue for each instance of an object that produces events and occasionally poll the queue for its contents when they are desired.
Give me a detailed explaination of how you would like it to work, and I'll see if there is something that I can do.

As far I'm concerned AngelScript works well in an event driven programming model. You'll just have to write an application object with which events and their corresponding script functions can be registered. The object would also have methods to raise events.

Example script:

void Init(){  eventMgr.RegisterEvent(HITME, "onHitMe");  eventMgr.NewEvent(HITME);}void onHitMe(){  print("A HitMe event occurred");}


When the event manager receives a call to NewEvent, it creates a context (or reuses an existing one) and calls the script function registered for that event.

Regards,
Andreas

PS. I will implement script function pointers soon, which may help in this regard.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
Yeah, for the general case Angelscript works really well. For my case, all events must be able to notify the main executing script. For my users, think of the script as their application. When the script stops, that is the equivalent of program termination. Starting a new script is the equivalent of launching a new program.

I'll have to think a little while as to what my particular needs are but what I can initially tell is something along these lines:

Main script begins execution.
Script registers functions to handle desired events.
Script creates GUI.
User interacts with GUI.
GUI fires event.
Event handler executes and interacts with main script to notify it of
any user actions.


For example lets say I have this situation.

The main script has an array of integers. Everytime the user presses a button on the GUI, a corresponding integer is placed into the vector.
The main script then does some processing on the contents of the array.

perhaps something like this:
int[] myArrray;void main(){  CreateGUI();  while(!done)      HandleEvents()}void CreateGUI(){     Button b(5, 5, 5, 5);     b.OnClick = HandleClick;}void HandleClick(int myargs){     myArray.PushBack(myargs);}


The example obviously is incomplete, but it should show the general idea.

Perhaps something like this is already possible, or can be easily done.
This is definitely possible already.

Since your main script is a long running script, and you want to be able to call other scripts without having to wait for the main script to terminate, you'll have to do a little scripted "multi-threading". You'll have to execute a small part of the main script, pause it, verify if the user has clicked on some GUI elements, call the event scripts, then resume execution of the main script. This is all done in a single OS thread, but to the script it will look like it was done in a multithreaded way.

You can use the line callback to suspend the main script after a short while.



AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Actually, I think I will write a small sample showing how this could work. It will be simple, no GUI, but will show how a long running script can interact with event based script calls.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Here's a preview of the new sample application. It might give you some idea that you can use for your application.

#include <iostream>  // cout#include <assert.h>  // assert()#include <conio.h>   // kbhit(), getch()#include <windows.h> // timeGetTime()#include <angelscript.h>#include "../../../add_on/scriptstring/scriptstring.h"using namespace std;// Function prototypesvoid ConfigureEngine(asIScriptEngine *engine);int  CompileScript(asIScriptEngine *engine);void PrintString(string &str);void LineCallback(asIScriptContext *ctx, DWORD *timeOut);int main(int argc, char **argv){	int r;	// Create the script engine	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);	if( engine == 0 )	{		cout << "Failed to create script engine." << endl;		return -1;	}	// Configure the script engine with all the functions, 	// and variables that the script should be able to use.	ConfigureEngine(engine);		// Compile the script code	r = CompileScript(engine);	if( r < 0 ) return -1;	// Create a script context that will execute the long running script	asIScriptContext *ctx;	r = engine->CreateContext(&ctx);	if( r < 0 ) 	{		cout << "Failed to create the context." << endl;		return -1;	}	// Prepare the script context with the function we wish to execute	r = ctx->Prepare(engine->GetFunctionIDByDecl(0, "void main()"));	if( r < 0 ) 	{		cout << "Failed to prepare the context." << endl;		return -1;	}	// Set the line callback so that we can suspend the script execution	// after a certain time. Before executing the script the timeOut variable	// will be set to the time when the script must stop executing. This	// way we will be able to do more than one thing, almost at the same time.	DWORD timeOut;	r = ctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL);	if( r < 0 )	{		cout << "Failed to set the line callback function." << endl;		return -1;	}	// Print some useful information and start the input loop	cout << "Sample event driven script execution using AngelScript " << asGetLibraryVersion() << "." << endl;	cout << "The main script continuosly prints a short string." << endl;	cout << "Press any key to fire an event that will print another string." << endl;	cout << "Press ESC to terminate the application." << endl << endl;	DWORD time = timeGetTime();	for(;;)	{		// Check if any key was pressed		if( kbhit() )		{			int key = getch();			if( key == 27 ) 				break;			else			{				// Fire an event by calling the script function.				// Using ExecuteString() for this is actually rather slow.				// It would be more efficient to create a context outside				// the main loop. We would also determine and store the 				// function id of the event function outside the loop. At  				// this location we would then just prepare the context and 				// execute it. But, since I'm a bit lazy and don't need the 				// extra performance, I'll use ExecuteString().				engine->ExecuteString(0, "Print(\"event fired\\n\")");			}		}		// Allow the long running script to execute for 10ms		timeOut = timeGetTime() + 10;		r = ctx->Execute();		if( r != asEXECUTION_SUSPENDED )		{			cout << "The script execution finished early." << endl;			break;		}	}	// Abort the long running script.	// It would have been better to allow the script to terminate by itself,	// perhaps by setting a global variable that it would poll every now and 	// then. But Abort() can be used, and AngelScript makes sure everything	// is correctly freed.	ctx->Abort();	// We must release the context when no longer using it	ctx->Release();	// Release the engine	engine->Release();	return 0;}void ConfigureEngine(asIScriptEngine *engine){	int r;	// Register the script string type	// Look at the implementation for this function for more information  	// on how to register a custom string type, and other object types.	// The implementation is in "/add_on/scriptstring/scriptstring.cpp"	RegisterScriptString(engine);	// Register the functions that the scripts will be allowed to use	r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 );	r = engine->RegisterGlobalFunction("uint GetSystemTime()", asFUNCTION(timeGetTime), asCALL_STDCALL); assert( r >= 0 );}class asCOutputStream : public asIOutputStream{public:	void Write(const char *text) { buffer += text; }	string buffer;};int CompileScript(asIScriptEngine *engine){	int r;	// This script prints a . approximately 10 times per second	const char *script = 	"void main()                       " 	"{                                 " 	 	"  uint time = GetSystemTime();    "	"  for(;;)                         "	"  {                               "	"    uint t = GetSystemTime();     "	"    if( t - time > 100 )          "	"    {                             "	"      time = t;                   "	"      Print(\".\");               "	"    }                             "                       	"  }                               "                                	"}                                 ";	// Add the script sections that will be compiled into executable code	r = engine->AddScriptSection(0, "script", script, strlen(script), 0, false);	if( r < 0 ) 	{		cout << "AddScriptSection() failed" << endl;		return -1;	}	// The script compiler will send any compiler messages to the outstream	asCOutputStream out;	// Compile the script	r = engine->Build(0, &out);	if( r < 0 )	{		cout << "Build() failed" << endl;		return -1;	}	return 0;}void PrintString(string &str){	cout << str;}void LineCallback(asIScriptContext *ctx, DWORD *timeOut){	// If the time out is reached we suspend the script	if( *timeOut < timeGetTime() )		ctx->Suspend();}


regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
Perhaps I am dumb, but I am not seeing how pausing the main script context and executing another function and restarting the original context will directly affect the main context. My goal is to have the event handling function directly manipulate variables declared in the main script.
Global variables declared in a module are shared between contexts, thus one context can affect the variables in the other. They just cannot manipulate variables on the function stack.

I'll update the sample to show that the variables are shared.

The name asIScriptContext is actually slightly misleading, and I intend to change it to asIScriptThread in a future version. asIScriptThread would more closely show what the role of the interface is.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Ahh, yeah, that is where i was being confused. That makes it clear now.
I agree, naming it asScriptThread() makes more sense and it's what people are used to when thinking about prog. langs. Context is more of an api term.

This topic is closed to new replies.

Advertisement