File: main.cpp

package info (click to toggle)
angelscript 2.35.1%2Bds-3.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,388 kB
  • sloc: cpp: 71,969; asm: 1,558; makefile: 665; xml: 214; javascript: 42; ansic: 22; python: 22; sh: 7
file content (337 lines) | stat: -rw-r--r-- 9,819 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#include <iostream>  // cout
#include <assert.h>  // assert()
#include <string.h>  // strstr()
#ifdef __unix__
	#include <sys/time.h>
	#include <stdio.h>
	#include <termios.h>
	#include <unistd.h>
	#include <fcntl.h>
	#include <string.h>
#else
	#include <conio.h>   // kbhit(), getch()
	#include <windows.h> // timeGetTime()
	#include <crtdbg.h>  // debugging routines
#endif
#include <angelscript.h>
#include "../../../add_on/scriptstdstring/scriptstdstring.h"

using namespace std;

#ifdef __unix__

#define UINT unsigned int 
typedef unsigned int DWORD;
int g_ch;
// Linux doesn't have timeGetTime(), this essentially does the same
// thing, except this is milliseconds since Epoch (Jan 1st 1970) instead
// of system start. It will work the same though...
DWORD timeGetTime()
{
	timeval time;
	gettimeofday(&time, NULL);
	return time.tv_sec*1000 + time.tv_usec/1000;
}

// Linux does have a getch() function in the curses library, but it doesn't
// work like it does on DOS. So this does the same thing, with out the need
// of the curses library.
int getch() 
{
	return g_ch;
}
// kbhit() for linux
int kbhit() 
{
	struct termios oldt, newt;
	int ch;
	int oldf;

	tcgetattr(STDIN_FILENO, &oldt);
	newt = oldt;
	newt.c_lflag &= ~(ICANON | ECHO);
	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
	oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

	ch = getchar();

	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
	fcntl(STDIN_FILENO, F_SETFL, oldf);

	if(ch != EOF) 
	{
		// Don't put the char back on the stream
		//ungetc(ch, stdin);
		g_ch = ch;
		return 1;
	}

	return 0;
}

#endif

// Function prototypes
void ConfigureEngine(asIScriptEngine *engine);
int  CompileScript(asIScriptEngine *engine);
void PrintString(string &str);
void LineCallback(asIScriptContext *ctx, DWORD *timeOut);
void PrintString_Generic(asIScriptGeneric *gen);
void timeGetTime_Generic(asIScriptGeneric *gen);

void MessageCallback(const asSMessageInfo *msg, void *param)
{
	const char *type = "ERR ";
	if( msg->type == asMSGTYPE_WARNING ) 
		type = "WARN";
	else if( msg->type == asMSGTYPE_INFORMATION ) 
		type = "INFO";

	printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}

int main(int argc, char **argv)
{
	int r;

	// Create the script engine
	asIScriptEngine *engine = asCreateScriptEngine();
	if( engine == 0 )
	{
		cout << "Failed to create script engine." << endl;
		return -1;
	}

	// The script compiler will send any compiler messages to the callback
	engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);

	// 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 two contexts, one will run the script thread 
	// that executes the main function, the other will other
	// be used to execute the event functions as needed.
	// Note that the global variables declared in the script
	// are shared between the contexts, so they are able to
	// communicate with each other this way.
	asIScriptContext *mainCtx = engine->CreateContext();
	if( mainCtx == 0 ) 
	{
		cout << "Failed to create the context." << endl;
		return -1;
	}

	asIScriptContext *eventCtx = engine->CreateContext();
	if( eventCtx == 0 )
	{
		cout << "Failed to create the context." << endl;
		return -1;
	}

	// Prepare the script context with the function we wish to execute
	r = mainCtx->Prepare(engine->GetModule(0)->GetFunctionByDecl("void main()"));
	if( r < 0 ) 
	{
		cout << "Failed to prepare the context." << endl;
		return -1;
	}

	// Get the function IDs for the event functions already
	asIScriptFunction *onKeyPressFunc = engine->GetModule(0)->GetFunctionByDecl("void OnKeyPress()");
	asIScriptFunction *onQuitFunc = engine->GetModule(0)->GetFunctionByDecl("void OnQuit()");

	// 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 = mainCtx->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();
	DWORD quitTimeOut = 0;

	for(;;)
	{
		// Check if any key was pressed
		if( kbhit() )
		{
			int key = getch();
			if( key != 27 ) 
			{
				// Fire an event by calling the script function.
				eventCtx->Prepare(onKeyPressFunc);
				eventCtx->Execute();

				// Note, I'm being a little lazy here, since we don't 
				// verify the return codes. Neither do I add any safeguard 
				// against never ending scripts, which if the script is 
				// badly written could cause the program to hang, I do this 
				// for the main script though.
			}
			else
			{
				// Fire the quit event that will tell the main script to finish
				eventCtx->Prepare(onQuitFunc);
				eventCtx->Execute();
				
				// Let the script run for at most 1sec more, to give it time 
				// to quit graciously. If it does not finish in time the 
				// script will be aborted.
				quitTimeOut = timeGetTime() + 1000;
			}
		}

		// Allow the long running script to execute for 10ms
		timeOut = timeGetTime() + 10;
		r = mainCtx->Execute();
		if( r != asEXECUTION_SUSPENDED )
		{
			if( quitTimeOut == 0 )
				cout << "The script execution finished early." << endl;
			break;
		}
		
		if( quitTimeOut && quitTimeOut < timeGetTime() )
		{
			// Abort the long running script.
			// AngelScript makes sure everything is correctly freed.
			mainCtx->Abort();
			break;
		}
	}

	// We must release the contexts when no longer using them
	mainCtx->Release();
	eventCtx->Release();

	// Shut down the engine
	engine->ShutDownAndRelease();

	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.
	RegisterStdString(engine);

	// Register the functions that the scripts will be allowed to use
	if( !strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		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 );
	}
	else
	{
		r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString_Generic), asCALL_GENERIC); assert( r >= 0 );
		r = engine->RegisterGlobalFunction("uint GetSystemTime()", asFUNCTION(timeGetTime_Generic), asCALL_GENERIC); assert( r >= 0 );
	}
}

int CompileScript(asIScriptEngine *engine)
{
	int r;

	// This script prints a char approximately 10 times per second
	const char *scriptMain = 
	"string char = \"-\";               "
	"bool doQuit = false;               "
	"void main()                        "
	"{                                  "
	"  uint time = GetSystemTime();     "
	"  while( !doQuit )                 "
	"  {                                "
	"    uint t = GetSystemTime();      "
	"    if( t - time > 100 )           "
	"    {                              "
	"      time = t;                    "
	"      Print(char);                 "
	"    }                              "
	"  }                                "
	"}                                  ";
	
	const char *scriptEvents =
	"void OnKeyPress()                  "
	"{                                  "
	"  Print(\"A key was pressed\\n\"); "
	"  if( char == \"-\" )              "
	"    char = \"+\";                  "
	"  else                             "
	"    char = \"-\";                  "
	"}                                  "
	"void OnQuit()                      "
	"{                                  "
	"  doQuit = true;                   "
	"}                                  ";

	// Add the script sections that will be compiled into executable code
	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	r = mod->AddScriptSection("scriptMain", scriptMain, strlen(scriptMain));
	if( r < 0 ) 
	{
		cout << "AddScriptSection() failed" << endl;
		return -1;
	}
	
	r = mod->AddScriptSection("scriptEvents", scriptEvents, strlen(scriptEvents));
	if( r < 0 )
	{
		cout << "AddScriptSection() failed" << endl;
		return -1;
	}

	// Compile the script
	r = mod->Build();
	if( r < 0 )
	{
		cout << "Build() failed" << endl;
		return -1;
	}

	return 0;
}

void PrintString(string &str)
{
	cout << str;
}

void PrintString_Generic(asIScriptGeneric *gen)
{
	string *str = (string*)gen->GetArgAddress(0);
	PrintString(*str);
}

void timeGetTime_Generic(asIScriptGeneric *gen)
{
	gen->SetReturnDWord(timeGetTime());
}

void LineCallback(asIScriptContext *ctx, DWORD *timeOut)
{
	// If the time out is reached we suspend the script
	if( *timeOut < timeGetTime() )
		ctx->Suspend();
}