| 1 |
// OSRail -- a network enabled railroad operations simulator and utilities |
|---|
| 2 |
// Copyright (C) 2007,2008 Samuel E. Henley sehenley@comcast.net |
|---|
| 3 |
// |
|---|
| 4 |
// This program is free software; you can redistribute it and/or modify |
|---|
| 5 |
// it under the terms of the GNU General Public License as published by |
|---|
| 6 |
// the Free Software Foundation; either version 2 of the License, or |
|---|
| 7 |
// (at your option) any later version. |
|---|
| 8 |
// |
|---|
| 9 |
// This program is distributed in the hope that it will be useful, |
|---|
| 10 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 |
// GNU General Public License for more details. |
|---|
| 13 |
// |
|---|
| 14 |
// You should have received a copy of the GNU General Public License along |
|---|
| 15 |
// with this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 16 |
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|---|
| 17 |
// |
|---|
| 18 |
/// \file |
|---|
| 19 |
/// Implementation file for Task manager of the simulator and the ITask factory. |
|---|
| 20 |
|
|---|
| 21 |
// Pre-Compiled Header for Simulator |
|---|
| 22 |
#include "presimulator.h" |
|---|
| 23 |
|
|---|
| 24 |
#include "task.h" |
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
/// \addtogroup simulator "Simulator" |
|---|
| 28 |
/// @{ |
|---|
| 29 |
/// \addtogroup simulatorcomponent "Simulator Components" |
|---|
| 30 |
/// @{ |
|---|
| 31 |
/// \addtogroup task "Task" |
|---|
| 32 |
/// @{ |
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
extern ITask* createTask( ISystem& sys ) |
|---|
| 36 |
{ |
|---|
| 37 |
return new Task( sys ); |
|---|
| 38 |
} |
|---|
| 39 |
|
|---|
| 40 |
Task::Task( ISystem& sys ) : system( sys ), engine(0) |
|---|
| 41 |
{ |
|---|
| 42 |
} |
|---|
| 43 |
|
|---|
| 44 |
Task::~Task() |
|---|
| 45 |
{ |
|---|
| 46 |
} |
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 |
|
|---|
| 50 |
//vertual |
|---|
| 51 |
void Task::startup() |
|---|
| 52 |
{ |
|---|
| 53 |
MESSAGE( "Simulator", "Task", "Startup" ) |
|---|
| 54 |
error.resize( 1024 ); //Common error buffer |
|---|
| 55 |
configureScriptEngine(); |
|---|
| 56 |
} |
|---|
| 57 |
|
|---|
| 58 |
//virtual |
|---|
| 59 |
void Task::operator()() |
|---|
| 60 |
{ |
|---|
| 61 |
if( compiles.empty() ) |
|---|
| 62 |
{ |
|---|
| 63 |
if( !scripts.empty() ) |
|---|
| 64 |
{ |
|---|
| 65 |
int id = scripts.top().context->GetCurrentFunction(); |
|---|
| 66 |
const_cast<Script&>(scripts.top()).timeout = scripts.top().max + system.getFrameMilliseconds(); |
|---|
| 67 |
scripts.top().context->SetLineCallback( asFUNCTION(taskLineCallback), this, asCALL_CDECL ); |
|---|
| 68 |
scripts.top().context->SetExceptionCallback( asFUNCTION(taskExceptionCallback), this, asCALL_CDECL ); |
|---|
| 69 |
|
|---|
| 70 |
int result = scripts.top().context->Execute(); |
|---|
| 71 |
if( result < 0 ) |
|---|
| 72 |
{ |
|---|
| 73 |
asIScriptFunction* fd = engine->GetFunctionDescriptorById( id ); |
|---|
| 74 |
sprintf( &error[0], "Could not execute function %s", fd->GetName() ); |
|---|
| 75 |
ASSERT( false, "Simulator", "Task", &error[0] ) |
|---|
| 76 |
scripts.top().context->Release(); |
|---|
| 77 |
scripts.pop(); |
|---|
| 78 |
} |
|---|
| 79 |
else |
|---|
| 80 |
{ |
|---|
| 81 |
switch( result ) |
|---|
| 82 |
{ |
|---|
| 83 |
case asEXECUTION_SUSPENDED : |
|---|
| 84 |
break; |
|---|
| 85 |
|
|---|
| 86 |
case asEXECUTION_ABORTED : |
|---|
| 87 |
case asEXECUTION_EXCEPTION : |
|---|
| 88 |
case asEXECUTION_FINISHED : |
|---|
| 89 |
scripts.top().context->Release(); |
|---|
| 90 |
scripts.pop(); |
|---|
| 91 |
break; |
|---|
| 92 |
|
|---|
| 93 |
default: |
|---|
| 94 |
{ |
|---|
| 95 |
asIScriptFunction* fd = engine->GetFunctionDescriptorById( id ); |
|---|
| 96 |
sprintf( &error[0], "Program logic error, result from AngelScript Execute unrecognized module %s", fd->GetModuleName() ); |
|---|
| 97 |
ASSERT( false, "ScriptManager", "Task", &error[0] ) |
|---|
| 98 |
} |
|---|
| 99 |
break; |
|---|
| 100 |
} |
|---|
| 101 |
} |
|---|
| 102 |
} |
|---|
| 103 |
} |
|---|
| 104 |
else |
|---|
| 105 |
{ |
|---|
| 106 |
const Compile& it = compiles.top(); |
|---|
| 107 |
asIScriptModule* module = engine->GetModule( it.module.c_str(), asGM_ALWAYS_CREATE ); |
|---|
| 108 |
module->AddScriptSection( "script", it.script.c_str(), it.script.length(), 0 ); |
|---|
| 109 |
if( module->Build() < 0 ) |
|---|
| 110 |
{ |
|---|
| 111 |
sprintf( &error[0], "Did not create script context for script module %s", it.module.c_str()); |
|---|
| 112 |
ASSERT( false, "Simulator", "Task", &error[0] ) |
|---|
| 113 |
} |
|---|
| 114 |
else |
|---|
| 115 |
{ |
|---|
| 116 |
size_t size = module->GetFunctionCount(); |
|---|
| 117 |
for( size_t i=0; i<size; i++ ) |
|---|
| 118 |
{ |
|---|
| 119 |
asIScriptContext* context = engine->CreateContext(); |
|---|
| 120 |
if( !context ) |
|---|
| 121 |
{ |
|---|
| 122 |
sprintf( &error[0], "Could not create context for script module %s", it.module.c_str()); |
|---|
| 123 |
ASSERT( false, "ScriptManager", "Task", &error[0] ) |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
int id = module->GetFunctionIdByIndex( i ); |
|---|
| 127 |
if( context->Prepare( id ) < 0 ) |
|---|
| 128 |
{ |
|---|
| 129 |
sprintf( &error[0], "Could not Prepare context for script module %s", it.module.c_str()); |
|---|
| 130 |
ASSERT( false, "ScriptManager", "Task", &error[0] ) |
|---|
| 131 |
context->Release(); |
|---|
| 132 |
} |
|---|
| 133 |
else |
|---|
| 134 |
{ |
|---|
| 135 |
Script ss; |
|---|
| 136 |
ss.context = context; |
|---|
| 137 |
ss.priority = it.priority; |
|---|
| 138 |
ss.context->SetUserData( reinterpret_cast<void*>(this) ); |
|---|
| 139 |
ss.max = it.max; |
|---|
| 140 |
ss.timeout = 0; |
|---|
| 141 |
scripts.push( ss ); |
|---|
| 142 |
} |
|---|
| 143 |
} |
|---|
| 144 |
} |
|---|
| 145 |
|
|---|
| 146 |
compiles.pop(); |
|---|
| 147 |
} |
|---|
| 148 |
} |
|---|
| 149 |
|
|---|
| 150 |
//virtual |
|---|
| 151 |
void Task::shutdown() |
|---|
| 152 |
{ |
|---|
| 153 |
while( !scripts.empty() ) |
|---|
| 154 |
{ |
|---|
| 155 |
scripts.top().context->Release(); |
|---|
| 156 |
scripts.pop(); |
|---|
| 157 |
} |
|---|
| 158 |
if( engine )engine->Release(); |
|---|
| 159 |
engine = 0; |
|---|
| 160 |
MESSAGE( "Simulator", "Task", "Cleanup scripts" ) |
|---|
| 161 |
MESSAGE( "Simulator", "Task", "Shutdown" ) |
|---|
| 162 |
} |
|---|
| 163 |
|
|---|
| 164 |
//virtual |
|---|
| 165 |
bool Task::addScript( const char* module, const char* script, const clock_t max /*= 10*/, const int priority /*= 0*/ ) |
|---|
| 166 |
{ |
|---|
| 167 |
ASSERT( engine != 0, "ScriptManager", "Task", "addScript called with no script engine" ) |
|---|
| 168 |
Compile cc; |
|---|
| 169 |
cc.module = module; |
|---|
| 170 |
cc.script = script; |
|---|
| 171 |
cc.max = max; |
|---|
| 172 |
compiles.push( cc ); |
|---|
| 173 |
|
|---|
| 174 |
return true; |
|---|
| 175 |
} |
|---|
| 176 |
|
|---|
| 177 |
//static |
|---|
| 178 |
void Task::taskMessageCallback( const asSMessageInfo* msg, void* param ) |
|---|
| 179 |
{ |
|---|
| 180 |
/// \todo Move script error to Console, or logger. |
|---|
| 181 |
String type; |
|---|
| 182 |
switch( msg->type ) |
|---|
| 183 |
{ |
|---|
| 184 |
case asMSGTYPE_ERROR : type = _(" error="); break; |
|---|
| 185 |
case asMSGTYPE_WARNING : type = _(" warning="); break; |
|---|
| 186 |
case asMSGTYPE_INFORMATION : type = _(" information=");break; |
|---|
| 187 |
default : type = _("?"); |
|---|
| 188 |
ASSERT( false, "Simulator", "Task", "Program error AngelScript message type" ) // How did we get here? |
|---|
| 189 |
} |
|---|
| 190 |
|
|---|
| 191 |
std::vector<char> error; |
|---|
| 192 |
error.resize( 1024 ); |
|---|
| 193 |
sprintf( &error[0], "%s row=%d col=%d %s %s", |
|---|
| 194 |
msg->section, |
|---|
| 195 |
msg->row, |
|---|
| 196 |
msg->col, |
|---|
| 197 |
type.c_str(), |
|---|
| 198 |
msg->message ); |
|---|
| 199 |
|
|---|
| 200 |
MESSAGE( "Simulator", "Task", &error[0] ) |
|---|
| 201 |
} |
|---|
| 202 |
|
|---|
| 203 |
void Task::taskTimeout( asIScriptContext* context ) |
|---|
| 204 |
{ |
|---|
| 205 |
if( scripts.top().timeout < system.getFrameMilliseconds() ) |
|---|
| 206 |
{ |
|---|
| 207 |
context->Suspend(); |
|---|
| 208 |
} |
|---|
| 209 |
} |
|---|
| 210 |
|
|---|
| 211 |
void Task::taskException( asIScriptContext* context ) |
|---|
| 212 |
{ |
|---|
| 213 |
context->Suspend(); |
|---|
| 214 |
int id = context->GetCurrentFunction(); |
|---|
| 215 |
asIScriptFunction* fd = engine->GetFunctionDescriptorById( id ); |
|---|
| 216 |
sprintf( &error[0], "Exception in function %s", fd->GetName() ); |
|---|
| 217 |
ASSERT( false, "Simulator", "Task", &error[0] ) |
|---|
| 218 |
scripts.top().context->Release(); |
|---|
| 219 |
scripts.pop(); |
|---|
| 220 |
} |
|---|
| 221 |
|
|---|
| 222 |
//static |
|---|
| 223 |
void Task::taskLineCallback( asIScriptContext* context, asDWORD* task ) |
|---|
| 224 |
{ |
|---|
| 225 |
ASSERT( task, "Simulator", "Task", "Programing error callback Task::taskLineCallback has no object pointer" ) |
|---|
| 226 |
(reinterpret_cast<Task*>(task))->taskTimeout( context ); |
|---|
| 227 |
} |
|---|
| 228 |
|
|---|
| 229 |
//static |
|---|
| 230 |
void Task::taskExceptionCallback( asIScriptContext* context, asDWORD* task ) |
|---|
| 231 |
{ |
|---|
| 232 |
ASSERT( task, "Simulator", "Task", "Script error callback Task::taskExceptionCallback called" ) |
|---|
| 233 |
(reinterpret_cast<Task*>(task))->taskException( context ); |
|---|
| 234 |
} |
|---|
| 235 |
|
|---|
| 236 |
/// \note Script interfaces to simulator |
|---|
| 237 |
IAi* g_ai = 0; |
|---|
| 238 |
IConsoleClient* g_console = 0; |
|---|
| 239 |
IFactory* g_factory = 0; |
|---|
| 240 |
IGraphics* g_graphics = 0; |
|---|
| 241 |
IGui* g_gui = 0; |
|---|
| 242 |
IInput* g_input = 0; |
|---|
| 243 |
INetwork* g_network = 0; |
|---|
| 244 |
IPropertyManager* g_propertymanager = 0; |
|---|
| 245 |
ISimulation* g_simulation = 0; |
|---|
| 246 |
ISound* g_sound = 0; |
|---|
| 247 |
ISystem* g_system = 0; |
|---|
| 248 |
ITask* g_task = 0; |
|---|
| 249 |
ITest* g_test = 0; |
|---|
| 250 |
|
|---|
| 251 |
|
|---|
| 252 |
/// Wrapper for ITask::addScript |
|---|
| 253 |
bool ITask_addScript_Wrapper( CScriptString& name, CScriptString& script, const int max, const int priority, ITask* task ) |
|---|
| 254 |
{ |
|---|
| 255 |
return task->addScript( name.buffer.c_str(), script.buffer.c_str(), max, priority ); |
|---|
| 256 |
} |
|---|
| 257 |
|
|---|
| 258 |
//private |
|---|
| 259 |
void Task::configureScriptEngine() |
|---|
| 260 |
{ |
|---|
| 261 |
// initialize system interfaces, must initialize ITask last in ISystem startup. |
|---|
| 262 |
g_ai = system.getAiInterface(); |
|---|
| 263 |
g_console = system.getConsoleClientInterface(); |
|---|
| 264 |
g_factory = system.getFactoryInterface(); |
|---|
| 265 |
g_graphics = system.getGraphicsInterface(); |
|---|
| 266 |
g_gui = system.getGuiInterface(); |
|---|
| 267 |
g_input = system.getInputInterface(); |
|---|
| 268 |
g_network = system.getNetworkInterface(); |
|---|
| 269 |
g_propertymanager = system.getPropertyManagerInterface(); |
|---|
| 270 |
g_simulation = system.getSimulationInterface(); |
|---|
| 271 |
g_sound = system.getSoundInterface(); |
|---|
| 272 |
g_system = system.getSystemInterface(); |
|---|
| 273 |
g_task = system.getTaskInterface(); |
|---|
| 274 |
g_test = system.getTestInterface(); |
|---|
| 275 |
|
|---|
| 276 |
ASSERT( engine == 0, "Simulator", "Task", "Program error AngelScript engine already created" ) |
|---|
| 277 |
engine = asCreateScriptEngine( ANGELSCRIPT_VERSION ); |
|---|
| 278 |
ASSERT( engine, "Simulator", "Task", "Could not create AngelScript engine" ) |
|---|
| 279 |
engine->SetMessageCallback( asFUNCTION(taskMessageCallback), 0, asCALL_CDECL ); |
|---|
| 280 |
MESSAGE( "Simulator", "Task", "Initialized scripts" ) |
|---|
| 281 |
|
|---|
| 282 |
RegisterScriptString( engine ); |
|---|
| 283 |
|
|---|
| 284 |
// ISystem |
|---|
| 285 |
VERIFY(( engine->RegisterObjectType("ISystem", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register ISystem interface" ) |
|---|
| 286 |
VERIFY(( engine->RegisterObjectMethod( "ISystem", "bool running()", asMETHOD( ISystem, running ), asCALL_THISCALL ) >= 0 ), |
|---|
| 287 |
"Simulator", "Task", "Could not register ISystem::running interface" ) |
|---|
| 288 |
VERIFY(( engine->RegisterGlobalProperty( "ISystem system", &g_system ) >= 0 ), "Simulator", "Task", "Unable add properity system to AngelScript Engine" ) |
|---|
| 289 |
|
|---|
| 290 |
VERIFY(( engine->RegisterObjectType("IGraphics", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register IGraphics interface" ) |
|---|
| 291 |
VERIFY(( engine->RegisterObjectMethod( "IGraphics", "bool isClosed()", asMETHOD( IGraphics, isClosed ), asCALL_THISCALL ) >= 0 ), |
|---|
| 292 |
"Simulator", "Task", "Could not register IGraphics::isClosed interface" ) |
|---|
| 293 |
VERIFY(( engine->RegisterObjectMethod( "IGraphics", "bool isVisible()", asMETHOD( IGraphics, isVisible ), asCALL_THISCALL ) >= 0 ), |
|---|
| 294 |
"Simulator", "Task", "Could not register IGraphics::isVisible interface" ) |
|---|
| 295 |
VERIFY(( engine->RegisterGlobalProperty( "IGraphics graphics", &g_graphics ) >= 0 ), "Simulator", "Task", "Unable add properity graphics to AngelScript Engine" ) |
|---|
| 296 |
|
|---|
| 297 |
// ITask |
|---|
| 298 |
VERIFY(( engine->RegisterObjectType( "ITask", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register ITask interface" ) |
|---|
| 299 |
VERIFY(( engine->RegisterObjectMethod( "ITask", "bool addScript( const string &in name, const string &in script, const int &in max, const int &in priority )", |
|---|
| 300 |
asFUNCTION( ITask_addScript_Wrapper ), asCALL_CDECL_OBJLAST ) >= 0 ), |
|---|
| 301 |
"Simulator", "Task", "Could not register ITask::addScript (ITask_addScript_Wrapper) interface" ) |
|---|
| 302 |
VERIFY(( engine->RegisterGlobalProperty( "ITask task", &g_task ) >= 0 ), "Simulator", "Task", "Unable add properity task to AngelScript Engine" ) |
|---|
| 303 |
|
|---|
| 304 |
// ISound |
|---|
| 305 |
VERIFY(( engine->RegisterObjectType("ISound", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register ISound interface" ) |
|---|
| 306 |
VERIFY(( engine->RegisterGlobalProperty( "ISound sound", &g_sound ) >= 0 ), "Simulator", "Task", "Unable add properity sound to AngelScript Engine" ) |
|---|
| 307 |
|
|---|
| 308 |
// IAi |
|---|
| 309 |
VERIFY(( engine->RegisterObjectType("IAi", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register IAi interface" ) |
|---|
| 310 |
VERIFY(( engine->RegisterGlobalProperty( "IAi ai", &g_ai ) >= 0 ), "Simulator", "Task", "Unable add properity ai to AngelScript Engine" ) |
|---|
| 311 |
|
|---|
| 312 |
// IInput |
|---|
| 313 |
VERIFY(( engine->RegisterObjectType("IInput", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register IInput interface" ) |
|---|
| 314 |
VERIFY(( engine->RegisterGlobalProperty( "IInput input", &g_input ) >= 0 ), "Simulator", "Task", "Unable add properity input to AngelScript Engine" ) |
|---|
| 315 |
|
|---|
| 316 |
// IGui |
|---|
| 317 |
VERIFY(( engine->RegisterObjectType("IGui", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register IGui interface" ) |
|---|
| 318 |
VERIFY(( engine->RegisterGlobalProperty( "IGui gui", &g_gui ) >= 0 ), "Simulator", "Task", "Unable add properity gui to AngelScript Engine" ) |
|---|
| 319 |
|
|---|
| 320 |
// INetwork |
|---|
| 321 |
VERIFY(( engine->RegisterObjectType("INetwork", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register INetwork interface" ) |
|---|
| 322 |
VERIFY(( engine->RegisterGlobalProperty( "INetwork network", &g_network ) >= 0 ), "Simulator", "Task", "Unable add properity network to AngelScript Engine" ) |
|---|
| 323 |
|
|---|
| 324 |
// IConsoleClient |
|---|
| 325 |
VERIFY(( engine->RegisterObjectType("IConsoleClient", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), |
|---|
| 326 |
"Simulator", "Task", "Could not register IConsoleClient interface" ) |
|---|
| 327 |
VERIFY(( engine->RegisterGlobalProperty( "IConsoleClient consoleclient", &g_console ) >= 0 ), "Simulator", "Task", "Unable add properity consoleclient to AngelScript Engine" ) |
|---|
| 328 |
|
|---|
| 329 |
// IFactory |
|---|
| 330 |
VERIFY(( engine->RegisterObjectType("IFactory", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register IFactory interface" ) |
|---|
| 331 |
VERIFY(( engine->RegisterGlobalProperty( "IFactory factory", &g_factory ) >= 0 ), "Simulator", "Task", "Unable add properity factory to AngelScript Engine" ) |
|---|
| 332 |
|
|---|
| 333 |
// IProperityManager |
|---|
| 334 |
VERIFY(( engine->RegisterObjectType("IPropertyManager", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), |
|---|
| 335 |
"Simulator", "Task", "Could not register IPropertyManager interface" ) |
|---|
| 336 |
VERIFY(( engine->RegisterGlobalProperty( "IPropertyManager propertymanager", &g_propertymanager ) >= 0 ), "Simulator", "Task", "Unable add properity propertymanager to AngelScript Engine" ) |
|---|
| 337 |
|
|---|
| 338 |
// ISimulation |
|---|
| 339 |
VERIFY(( engine->RegisterObjectType("ISimulation", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register ISimulation interface" ) |
|---|
| 340 |
VERIFY(( engine->RegisterGlobalProperty( "ISimulation simulation", &g_simulation ) >= 0 ), "Simulator", "Task", "Unable add properity simulation to AngelScript Engine" ) |
|---|
| 341 |
|
|---|
| 342 |
// Test |
|---|
| 343 |
VERIFY(( engine->RegisterObjectType("ITest", 0, asOBJ_REF|asOBJ_NOHANDLE ) >= 0 ), "Simulator", "Task", "Could not register ITest interface" ) |
|---|
| 344 |
VERIFY(( engine->RegisterGlobalProperty( "ITest test", &g_test ) >= 0 ), "Simulator", "Task", "Unable add properity test to AngelScript Engine" ) |
|---|
| 345 |
|
|---|
| 346 |
|
|---|
| 347 |
} |
|---|
| 348 |
|
|---|
| 349 |
|
|---|
| 350 |
|
|---|
| 351 |
|
|---|
| 352 |
|
|---|
| 353 |
/// @} group task |
|---|
| 354 |
/// @} group simulatorcomponent |
|---|
| 355 |
/// @} group simulator |
|---|