1 module as.engine; 2 import as.def; 3 import std..string; 4 import std.traits; 5 import as; 6 7 class ScriptEngine { 8 private: 9 asIScriptEngine* engine; 10 11 ~this() { 12 this.shutDownAndRelease(); 13 } 14 15 this(asIScriptEngine* engine) { 16 this.engine = engine; 17 } 18 19 public: 20 21 /** 22 Creates a new script engine 23 */ 24 static ScriptEngine create(asDWORD version_ = ANGELSCRIPT_VERSION) { 25 return new ScriptEngine(asCreateScriptEngine(version_)); 26 } 27 28 /** 29 Adds reference 30 */ 31 int addRef() { 32 return asEngine_AddRef(engine); 33 } 34 35 /** 36 Releases reference 37 */ 38 int release() { 39 return asEngine_Release(engine); 40 } 41 42 /** 43 Shuts down the scripting engine and releases it 44 */ 45 int shutDownAndRelease() { 46 return asEngine_ShutDownAndRelease(engine); 47 } 48 49 /** 50 Sets an engine property 51 */ 52 void setProperty(asEEngineProp property, asPWORD value) { 53 int err = asEngine_SetEngineProperty(engine, property, value); 54 assert(err != asERetCodes.asINVALID_ARG, "Invalid argument"); 55 } 56 57 /** 58 Gets an engine property 59 */ 60 asPWORD getProperty(asEEngineProp property) { 61 return asEngine_GetEngineProperty(engine, property); 62 } 63 64 /** 65 Sets the message callback 66 */ 67 void setMessageCallback(MessageCallback callback) { 68 int err = asEngine_SetMessageCallback(engine, cast(asFUNCTION_t)callback, null, CDECL); 69 assert(err != asERetCodes.asINVALID_ARG, "Invalid argument"); 70 assert(err != asERetCodes.asNOT_SUPPORTED, "Not supported"); 71 } 72 73 /** 74 Clears the message callback 75 */ 76 void clearMessageCallback() { 77 asEngine_ClearMessageCallback(engine); 78 } 79 80 /** 81 Writes a message 82 */ 83 void writeMessage(string section, int row, int col, MessageType type, string message) { 84 asEngine_WriteMessage(engine, section.toStringz, row, col, cast(asEMsgType)type, message.toStringz); 85 } 86 87 // TODO: Jit Compiler 88 89 /** 90 Register a global function 91 */ 92 void registerGlobalFunction(T)(string declaration, T func, void* aux = null) if (isFunctionPointer!T) { 93 int err = asEngine_RegisterGlobalFunction(engine, declaration.toStringz, cast(asFUNCTION_t)func, DCall, aux); 94 assert(err != asERetCodes.asNOT_SUPPORTED, "Not supported"); 95 assert(err != asERetCodes.asWRONG_CALLING_CONV, "Wrong calling convetion"); 96 assert(err != asERetCodes.asINVALID_DECLARATION, "Function declaration is invalid"); 97 assert(err != asERetCodes.asNAME_TAKEN, "Function name is already taken"); 98 assert(err != asERetCodes.asALREADY_REGISTERED, "Function is already registered"); 99 assert(err != asERetCodes.asINVALID_ARG, "Invalid argument"); 100 } 101 102 /** 103 Gets the amount of global functions 104 */ 105 asUINT getGlobalFunctionCount() { 106 return asEngine_GetGlobalFunctionCount(engine); 107 } 108 109 /** 110 Gets a global function by its index 111 */ 112 Function getGlobalFunctionByIndex(uint index) { 113 return new Function(this, asEngine_GetGlobalFunctionByIndex(engine, index)); 114 } 115 116 /** 117 Gets a global function by its declaration 118 */ 119 Function getGlobalFunctionByDecl(string decl) { 120 return new Function(this, asEngine_GetGlobalFunctionByDecl(engine, decl.toStringz)); 121 } 122 123 /** 124 Registers a global property 125 */ 126 void registerGlobalProperty(T)(string declaration, ref T pointer) { 127 int err = asEngine_RegisterGlobalProperty(engine, declaration.toStringz, cast(void*)&pointer); 128 assert(err != asERetCodes.asINVALID_DECLARATION, "Declaration is invalid"); 129 assert(err != asERetCodes.asINVALID_TYPE, "Declaration type is invalid"); 130 assert(err != asERetCodes.asINVALID_ARG, "Reference is null"); 131 assert(err != asERetCodes.asNAME_TAKEN, "Name is already taken"); 132 } 133 134 /** 135 Gets the count of global properties 136 */ 137 asUINT getGlobalPropertyCount() { 138 return asEngine_GetGlobalPropertyCount(engine); 139 } 140 141 /** 142 Gets a global property by its index 143 */ 144 void getGlobalPropertyByIndex(uint index, ref string name, ref string namespace, ref int typeId, ref bool isConst, ref string configGroup, void* ptr, ref asDWORD accessMask) { 145 const(char)* c_name; 146 const(char)* c_namespace; 147 int c_typeId; 148 bool c_isConst; 149 const(char)* c_configGroup; 150 void* c_ptr; 151 asDWORD c_accessMask; 152 153 int err = asEngine_GetGlobalPropertyByIndex(engine, index, &c_name, &c_namespace, &c_typeId, &c_isConst, &c_configGroup, &c_ptr, &c_accessMask); 154 assert(err != asERetCodes.asINVALID_ARG, "Index is too large"); 155 156 // move all this data to the appropriate place 157 name = cast(string)c_name.fromStringz.idup; 158 namespace = cast(string)c_namespace.fromStringz.idup; 159 typeId = c_typeId; 160 isConst = c_isConst; 161 configGroup = cast(string)c_configGroup.fromStringz.idup; 162 ptr = c_ptr; 163 accessMask = c_accessMask; 164 } 165 166 /** 167 Gets the index of a global property by its name 168 */ 169 int getGlobalPropertyIndexByName(string name) { 170 int err = asEngine_GetGlobalPropertyIndexByName(engine, name.toStringz); 171 assert(err != asERetCodes.asNO_GLOBAL_VAR, "No matching property was found"); 172 return err; 173 } 174 175 /** 176 Gets the index of a global property by its declaration 177 */ 178 int getGlobalPropertyIndexByDecl(string decl) { 179 int err = asEngine_GetGlobalPropertyIndexByDecl(engine, decl.toStringz); 180 assert(err != asERetCodes.asNO_GLOBAL_VAR, "No matching property was found"); 181 assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration"); 182 return err; 183 } 184 185 /** 186 Registers an object type 187 */ 188 void registerObjectType(string name, int byteSize, TypeFlags flags) { 189 int err = asEngine_RegisterObjectType(engine, name.toStringz, byteSize, flags); 190 assert(err != asERetCodes.asINVALID_ARG, "Invalid flags"); 191 assert(err != asERetCodes.asINVALID_NAME, "Invalid name"); 192 assert(err != asERetCodes.asALREADY_REGISTERED, "An object with the same name already exists"); 193 assert(err != asERetCodes.asNAME_TAKEN, "Name is already taken by an other symbol"); 194 assert(err != asERetCodes.asLOWER_ARRAY_DIMENSION_NOT_REGISTERED, "Registered array type element must be a primitive or registered type"); 195 assert(err != asERetCodes.asINVALID_TYPE, "Array type was malformed"); 196 assert(err != asERetCodes.asNOT_SUPPORTED, "Array type is not supported or already in use."); 197 } 198 199 /** 200 Registers a property for an object 201 */ 202 void registerObjectProperty(string obj, string decl, int byteOffset) { 203 int err = asEngine_RegisterObjectProperty(engine, obj.toStringz, decl.toStringz, byteOffset); 204 assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Object type was registered in a different config group"); 205 assert(err != asERetCodes.asINVALID_OBJECT, "obj does not specify an object type"); 206 assert(err != asERetCodes.asINVALID_TYPE, "obj parameter syntax invalid"); 207 assert(err != asERetCodes.asNAME_TAKEN, "Name conflicts with other members"); 208 } 209 210 /** 211 Registers a method for an object 212 */ 213 void registerObjectMethod(T)(string obj, string decl, T func, CallConv callConv = DCall, void* aux = null) if (isFunctionPointer!T) { 214 int err = asEngine_RegisterObjectMethod(engine, obj.toStringz, decl.toStringz, cast(asFUNCTION_t)func, callConv, aux); 215 assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Object type was registered in a different config group"); 216 assert(err != asERetCodes.asNOT_SUPPORTED, "The calling convention is not supported"); 217 assert(err != asERetCodes.asINVALID_TYPE, "obj parameter syntax invalid"); 218 assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration"); 219 assert(err != asERetCodes.asNAME_TAKEN, "Name conflicts with other members"); 220 assert(err != asERetCodes.asWRONG_CALLING_CONV, "The function's calling convention is not compatible with callConv"); 221 assert(err != asERetCodes.asALREADY_REGISTERED, "The method is already registered with the same parameter list"); 222 assert(err != asERetCodes.asINVALID_ARG, "aux pointer was not set according to calling convention"); 223 } 224 225 /** 226 Registers a behaviour for an object 227 */ 228 void registerObjectBehaviour(T)(string obj, Behaviours behaviour, string decl, T func, CallConv callConv = DCall, void* aux = null) if (isFunctionPointer!T) { 229 int err = asEngine_RegisterObjectBehaviour(engine, obj.toStringz, behaviour, decl.toStringz, cast(asFUNCTION_t)func, callConv, aux); 230 assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Object type was registered in a different config group"); 231 assert(err != asERetCodes.asINVALID_ARG, "obj not set, global behaviour given in behaviour or the objForThiscall pointer wasn't set correctly"); 232 assert(err != asERetCodes.asWRONG_CALLING_CONV, "The function's calling convention is not compatible with callConv"); 233 assert(err != asERetCodes.asNOT_SUPPORTED, "The calling convention or behaviour signature is not supported"); 234 assert(err != asERetCodes.asINVALID_TYPE, "Invalid obj parameter"); 235 assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration"); 236 assert(err != asERetCodes.asILLEGAL_BEHAVIOUR_FOR_TYPE, "Illegal behaviour for type"); 237 assert(err != asERetCodes.asALREADY_REGISTERED, "The method is already registered with the same parameter list"); 238 } 239 240 /** 241 Registers a new interface 242 */ 243 void registerInterface(string name) { 244 int err = asEngine_RegisterInterface(engine, name.toStringz); 245 assert(err != asERetCodes.asINVALID_NAME, "Name is null or reserved keyword"); 246 assert(err != asERetCodes.asALREADY_REGISTERED, "Object type with this name already exists"); 247 assert(err != asERetCodes.asERROR, "Name is not a proper identifier"); 248 assert(err != asERetCodes.asNAME_TAKEN, "Name is already used elsewhere"); 249 } 250 251 /** 252 Registers an interface method 253 */ 254 void registerInterfaceMethod(string intf, string decl) { 255 int err = asEngine_RegisterInterfaceMethod(engine, intf.toStringz, decl.toStringz); 256 assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Interface was registered in a different config group"); 257 assert(err != asERetCodes.asINVALID_TYPE, "intf is not an interface"); 258 assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration"); 259 assert(err != asERetCodes.asNAME_TAKEN, "Name is already taken"); 260 } 261 262 /** 263 Gets the count of the objects in the engine 264 */ 265 asUINT getObjectTypeCount() { 266 return asEngine_GetObjectTypeCount(engine); 267 } 268 269 /** 270 Gets the type info of an object by its index 271 */ 272 Type getObjectTypeByIndex(asUINT index) { 273 auto type = asEngine_GetObjectTypeByIndex(engine, index); 274 return type !is null ? new Type(this, type) : null; 275 } 276 277 /** 278 Registers a string factory type with the specified creation functions 279 */ 280 void registerStringFactory(string type, asGETSTRINGCONSTFUNC_t getStr, asRELEASESTRINGCONSTFUNC_t releaseStr, asGETRAWSTRINGDATAFUNC_t getRawStr) { 281 int err = asEngine_RegisterStringFactory(engine, type.toStringz, getStr, releaseStr, getRawStr); 282 assert(err != asERetCodes.asINVALID_ARG, "The factory is null"); 283 assert(err != asERetCodes.asINVALID_TYPE, "Type is not valid or it is a reference/handle."); 284 } 285 286 /** 287 Gets the return type id of the string type the factory returns 288 */ 289 asUINT getStringFactoryReturnTypeId(asDWORD* flags = null) { 290 asUINT err = asEngine_GetStringFactoryReturnTypeId(engine, flags); 291 assert(err != asERetCodes.asNO_FUNCTION, "String factory has not been registered"); 292 return err; 293 } 294 295 /** 296 Registers the default array type 297 */ 298 void registerDefaultArrayType(string type) { 299 int err = asEngine_RegisterDefaultArrayType(engine, type.toStringz); 300 assert(err != asERetCodes.asINVALID_TYPE, "Type is not a template type"); 301 } 302 303 /** 304 Gets the type id of the default array type 305 */ 306 int getDefaultArrayTypeId() { 307 int err = asEngine_GetDefaultArrayTypeId(engine); 308 assert(err != asERetCodes.asINVALID_TYPE, "Array type has not been registered"); 309 return err; 310 } 311 312 /** 313 Registers a D enum in Angelscript 314 */ 315 void registerEnum(T)() if (is(T == enum)) { 316 mixin("import ", moduleName!T, ";"); 317 registerEnum(T.stringof); 318 static foreach(member; __traits(allMembers, T)) { 319 registerEnumValue(T.stringof, member, cast(int)mixin(T.stringof, ".", member)); 320 } 321 } 322 323 /** 324 Registers an enum 325 */ 326 void registerEnum(string type) { 327 int err = asEngine_RegisterEnum(engine, type.toStringz); 328 assert(err != asERetCodes.asINVALID_NAME, "Invalid name"); 329 assert(err != asERetCodes.asALREADY_REGISTERED, "Already registered"); 330 assert(err != asERetCodes.asERROR, "Couldn't parse type"); 331 assert(err != asERetCodes.asNAME_TAKEN, "Name already taken"); 332 } 333 334 /** 335 Registers a value for the enum 336 */ 337 void registerEnumValue(string type, string name, int value) { 338 int err = asEngine_RegisterEnumValue(engine, type.toStringz, name.toStringz, value); 339 assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Wrong config group"); 340 assert(err != asERetCodes.asINVALID_TYPE, "Invalid type"); 341 assert(err != asERetCodes.asALREADY_REGISTERED, "Already registered"); 342 } 343 344 /** 345 Gets the amount of enums registered 346 */ 347 asUINT getEnumCount() { 348 return asEngine_GetEnumCount(engine); 349 } 350 351 /** 352 Gets the type of an enum by its index 353 */ 354 Type getEnumByindex(asUINT index) { 355 auto type = asEngine_GetEnumByIndex(engine, index); 356 return type !is null ? new Type(this, type) : null; 357 } 358 359 void registerFuncDef(string decl) { 360 int err = asEngine_RegisterFuncdef(engine, decl.toStringz); 361 assert(err != asERetCodes.asINVALID_ARG, "Declaration not given"); 362 assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid function definition"); 363 assert(err != asERetCodes.asNAME_TAKEN, "Name conflicts with an other name"); 364 } 365 366 /** 367 Gets the amount of enums registered 368 */ 369 asUINT getFuncdefConut() { 370 return asEngine_GetFuncdefCount(engine); 371 } 372 373 /** 374 Gets the type of a fundef by its index 375 */ 376 Type getFuncdefByIndex(asUINT index) { 377 auto type = asEngine_GetFuncdefByIndex(engine, index); 378 return type !is null ? new Type(this, type) : null; 379 } 380 381 /** 382 Starts a new dynamic configuration group 383 */ 384 void beginConfigGroup(string groupName) { 385 int err = asEngine_BeginConfigGroup(engine, groupName.toStringz); 386 assert(err != asERetCodes.asNAME_TAKEN, "Group name is already in use"); 387 assert(err != asERetCodes.asNOT_SUPPORTED, "Nested configuration groups isn't supported"); 388 } 389 390 /** 391 Ends the configuration group 392 */ 393 void endConfigGroup() { 394 int err = asEngine_EndConfigGroup(engine); 395 assert(err != asERetCodes.asERROR, "No configuration groups to end"); 396 } 397 398 /** 399 Removes a configuration group 400 */ 401 void removeConfigGroup(string groupName) { 402 int err = asEngine_RemoveConfigGroup(engine, groupName.toStringz); 403 assert(err != asERetCodes.asCONFIG_GROUP_IS_IN_USE, "Group is in use and can't be removed"); 404 } 405 406 /** 407 Sets the access mask that should be used for subsequent registered entities 408 */ 409 asDWORD setDefaultAccessMask(asDWORD defaultMask) { 410 return asEngine_SetDefaultAccessMask(engine, defaultMask); 411 } 412 413 /** 414 Sets the default namespace 415 */ 416 void setDefaultNamespace(string nameSpace) { 417 int err = asEngine_SetDefaultNamespace(engine, nameSpace.toStringz); 418 assert(err != asERetCodes.asINVALID_ARG, "Invalid namespace"); 419 } 420 421 /** 422 Gets the current default namespace 423 */ 424 string getDefaultNamespace() { 425 return cast(string)asEngine_GetDefaultNamespace(engine).fromStringz; 426 } 427 428 /** 429 Gets a module in the engine by name 430 */ 431 Module getModule(string name, ModuleCreateFlags flags = ModuleCreateFlags.OnlyIfExists) { 432 auto mod = asEngine_GetModule(engine, name.toStringz, flags); 433 return mod !is null ? new Module(this, mod) : null; 434 } 435 436 /** 437 Gets a module in the engine by index 438 */ 439 Module getModule(asUINT index) { 440 auto mod = asEngine_GetModuleByIndex(engine, index); 441 return mod !is null ? new Module(this, mod) : null; 442 } 443 444 /** 445 Discards a module by name 446 Note: Any class instances of the module in question will be rendered invalid. 447 */ 448 void discardModule(string name) { 449 asEngine_DiscardModule(engine, name.toStringz); 450 } 451 452 /** 453 Gets the count of modules 454 */ 455 asUINT getModuleCount() { 456 return asEngine_GetModuleCount(engine); 457 } 458 459 /** 460 Get a function by its ID in the engine 461 */ 462 Function getFunctionById(int funcId) { 463 return new Function(this, asEngine_GetFunctionById(engine, funcId)); 464 } 465 466 /** 467 Creates a new script context 468 */ 469 ScriptContext createContext() { 470 return new ScriptContext(this, asEngine_CreateContext(engine)); 471 } 472 }