Jump to content
  • Advertisement

BrianEmpson

Member
  • Content Count

    32
  • Joined

  • Last visited

Community Reputation

101 Neutral

About BrianEmpson

  • Rank
    Member
  1. BrianEmpson

    MySQL Database

    I've had good luck with mysql++. You can write a few wrapper functions to do what you want to do in C++ and call those functions from Angelscript as you please.
  2. BrianEmpson

    Null pointer access exception

    Yes, this worked wonderfully. I will look into caching...sounds like a good idea.
  3. BrianEmpson

    Null pointer access exception

    Alright, here is all of the code involved for the classes: (note that s32 in registered as a regular int) AngelScript console class: class Console { //Other funcs snipped s32 getWindowId() { s.print("Console::getWindowId()!\n"); //s.print(ID_GUI_CONSOLE_WINDOW); return ID_GUI_CONSOLE_WINDOW; } //Properties //------------------------------------ //Other properties snipped private s32 ID_GUI_CONSOLE_WINDOW; } C++ console class (gutted with relevant functions only): class Console { void init(); //This is called once the graphics environment is finished setting up, it creates the script console class. } void Console::init() //Attach this class to the script console, once the graphics engine is initialized { scriptConsole = graphics->getEngine()->getScriptManager()->getObject("ui","Console","()"); //Create a Console :3 if (scriptConsole == 0) graphics->stop(); else scriptConsole->AddRef(); //Store the object } //Script Manager asIScriptObject* ScriptManager::getObject(const std::string& moduleName,const std::string& objectName,const std::string& params) { // Get the object type asIScriptModule *module = engine->GetModule(moduleName.c_str()); if (module == 0) { ss.str(""); ss.clear(); ss<<"Attempted to use non-existent module "<<moduleName.c_str()<<".\n"; log->log(ss.str()); return 0; } asIObjectType *type = engine->GetObjectTypeById(module->GetTypeIdByDecl(objectName.c_str())); if (type == 0) { ss.str(""); ss.clear(); ss<<"Could not retrieve object type "<<objectName.c_str()<<".\n"; log->log(ss.str()); return 0; } // Get the factory function id from the object type std::string decl = objectName + " @" + objectName + params; int factoryId = type->GetFactoryIdByDecl(decl.c_str()); // Prepare the context to call the factory function asIScriptContext* ctx = prepareContext(factoryId); // Execute the call ctx->Execute(); // Get the object that was created //asIScriptObject* obj = *(asIScriptObject**)ctx->GetAddressOfReturnValue(); asIScriptObject* obj = (asIScriptObject*)ctx->GetReturnAddress(); if (obj == 0) { ss.str(""); ss.clear(); ss<<"Could not instanciate object "<<objectName.c_str()<<" from script.\n"; log->log(ss.str()); return 0; } returnContext(ctx); return obj; //Let the calling function determine if they want to save it or not :3 } void* ScriptManager::exec(asIScriptObject* obj,const std::string& function,const char retType,const char* types, ... ) { va_list vl; int r; va_start(vl,types); asIObjectType* type = obj->GetObjectType(); // Obtain the id of the class method irr::s32 funcId = type->GetMethodIdByDecl(function.c_str()); // Prepare the context for calling the method asIScriptContext* ctx = prepareContext(funcId); //Parse types and set arguments //types are: c - 8bit,w - 16bit,i - 32bit,q - 64bit,f - float,d - double,v - arg by Address,V - obj by address for(int i=0;types != '\0';i++) { switch(types) { case 'c': //8bit ctx->SetArgByte(i,(char)va_arg(vl,int)); break; case 'w': //16bit ctx->SetArgWord(i,(short)va_arg(vl,int)); break; case 'i': //32bit ctx->SetArgDWord(i,va_arg(vl,int)); break; case 'q': //64bit int ctx->SetArgQWord(i,va_arg(vl,long long)); break; case 'f': //float ctx->SetArgFloat(i,(float)va_arg(vl,double)); break; case 'd': //double ctx->SetArgDouble(i,va_arg(vl,double)); break; case 'v': //arg by addr ctx->SetArgAddress(i,va_arg(vl,void*)); break; case 'V': //obj by addr ctx->SetArgObject(i,va_arg(vl,void*)); break; default: break; } } va_end(vl); r = ctx->Execute(); if( r != asEXECUTION_FINISHED) { // The execution didn't complete as expected. Determine what happened. if( r == asEXECUTION_EXCEPTION) { // An exception occurred, let the script writer know what happened so it can be corrected. ss.str(""); ss.clear(); ss<<"Exception! Line: " << ctx->GetExceptionLineNumber() << " Func: " << engine->GetFunctionDescriptorById(ctx->GetExceptionFunction())->GetDeclaration() << "\nString: " << ctx->GetExceptionString() << ".\n"; log->log(ss.str()); return 0; } } //Check return type void* ret = 0; switch(retType) { case 'o': { ret = ctx->GetReturnAddress(); return ret; break; } case 'O': { ret = ctx->GetReturnObject(); return ret; } case 'v': { ret = ctx->GetAddressOfReturnValue(); return ret; } } // Clean up returnContext(ctx); return 0; } returnContext() and prepareContext are copies from your game example. It seems to work well. I haven't had time to rewrite the portions that use that code yet. Here is the actual call: int Console::getWindowId() { int* windowId; if(bBufferDumped == false) //This will be true when the console is ready. { return -1; } else { void* test = graphics->getEngine()->getScriptManager()->exec(scriptConsole,"int getWindowId()",'v',""); (void)0; int justADebuggingBreakpointPlaceholder = 4; //windowId = (int*) } //return *windowId; return -1; } Before the console gets created, the logger will still try to spit text out to it, which would cause a segfault or other nastyness, so the C++ class stores the text temporarily until the console class gets a signal to dump the text buffer to the script console class after it has been created, which it then does and sets the bBufferDumped flag to true. Then this getWindowId() gets executed whenever the GUI library senses a GUI event, and calls this function. Debugging reveals that my generic pointer, void* test is zero and an exception logged as above. So, the exec function takes a stored asIScriptObject, grabs the type, and calls the method signature in the second parameter. The third parameter is the return type, which is "return by value address" in this case. The fourth parameter is a string of variable types that the rest of the parameters occupy. Here is the call to getWindowId(): if (event.EventType == EET_GUI_EVENT) { s32 id = event.GUIEvent.Caller->getID(); irr::gui::IGUIEnvironment* env = graphics->device->getGUIEnvironment(); s32 consoleId = console->getWindowId(); //<------------------------------------------- static std::stringstream ss; ss.str(""); ss.clear(); ss << "GUI id: "<< id << " Console ID: " << consoleId << "\n"; log->log(ss.str()); if(id == consoleId) { console->updateElements(); } //etc... }
  4. BrianEmpson

    References and copy operator

    Have you tried using handles instead of copying by value?
  5. BrianEmpson

    Null pointer access exception

    Hello, I had a script class, defined as such: class Console { Console() { //Initialization... ID_GUI_CONSOLE_WINDOW = 100; } ~Console() { } void autocomplete() { } int getWindowId() { return ID_GUI_CONSOLE_WINDOW; } private int ID_GUI_CONSOLE_WINDOW; } The issue is with "s32 getWindowId()", when attempting to call this function, I get: Engine 0: Exception! Line: 0 Func: int Console::getWindowId() String: Null pointer access. When I change the return value to "void" so the function declaration reads "void getWindowId()" I can call the function fine, as well as all of the other functions in the class (all void). Is there something I'm not doing right? I tried the property accessors, but I still get that same error message. Thanks, Brian
  6. BrianEmpson

    Passing a null pointer

    Thank you, behc. Simply removing the &in on the values passed by value worked wonderfully. I was under the impression that you needed the &in all the time. Cool, thanks!
  7. BrianEmpson

    Passing a null pointer

    It seems there are deeper problems somewhere in the way I've registered or recieved these values, I updated the wrapper function: static irr::gui::IGUIWindow* addWindowWrapper(const irr::core::recti &a,bool b,const wchar_t* c,irr::gui::IGUIElement* d,s32 e,irr::gui::IGUIEnvironment* env) { d = 0; if (b == true) { std::cout<<"True\n"; } if (b == false) { std::cout<<"False\n"; } irr::core::stringw tempc(c); irr::core::stringc temp = tempc.c_str(); std::cout<<temp.c_str()<<"\n"; std::cout<<e<<"\n"; env->addWindow(a,b,c,d,e); } And I got: True False <gibberish> 31264416 The gibberish is probably because angelscript passed a stringw but the function is expecting a wchar_t* array. The rest I have no clue as to why it's getting mangled. Interestingly, apparently the only values getting passed correctly is the "recti" and "stringw" types. The rest appear to be garbage.
  8. BrianEmpson

    Passing a null pointer

    Hello! I have a function I am trying to pass a null (0) pointer to: virtual IGUIWindow * addWindow (const core::rect< s32 > &rectangle, bool modal=false, const wchar_t *text=0, IGUIElement *parent=0, s32 id=-1)=0 I registered it as: r = engine->RegisterObjectMethod("GEnvironment", "GWindow@ addWindow(const recti &in,bool &in,const stringw &in,GElement@ &in,s32 &in)", asMETHOD(irr::gui::IGUIEnvironment, addWindow), asCALL_THISCALL); assert(r >= 0); But I get a segfault when I try to create it in the script like this: @conWin = GUIEnv.addWindow(windowPos,false,consoleTitle,null,ID_GUI_CONSOLE_WINDOW); Normally, in C++, the equivalent call I am trying to make would be: recti windowPos = recti(50,50,400,450); stringw consoleTitle = L"Console" IGUIWindow* win = gui_env->addWindow(windowPos,false,consoleTitle,0,ID_GUI_CONSOLE_WINDOW); The only difference is the 4th field, null and 0 respectively. To troubleshoot, I made a wrapper function: static irr::gui::IGUIWindow* addWindowWrapper(const irr::core::recti &a,bool b,const wchar_t* c,irr::gui::IGUIElement* d,s32 e,irr::gui::IGUIEnvironment* env) { d = 0; env->addWindow(a,b,c,d,e); } And changed the registration call to: r = engine->RegisterObjectMethod("GEnvironment", "GWindow@ addWindow(const recti &in,bool &in,const stringw &in,GElement@ &in,s32 &in)", asFUNCTION(addWindowWrapper), asCALL_CDECL_OBJLAST); assert(r >= 0); In the wrapper, without the "d = 0" line to set the IGUIElement* pointer to 0, a value of 0xfffffff4 gets passed to the addWindow function, crashing it. So I have a work around in place, my question is, how do you pass a pointer to 0 from the script? null seems to equate to 0xfffffff4 as seen above. I tried inputting an int, but it messed up the declaration because I have other functions that expect a pointer to an IGUIElement and not null, so I need a handle in the script call somewhere. Any suggestions?
  9. BrianEmpson

    Determining Template Subtype in Factory

    Hmm, it would seem to me that registering the container types from irrLicht is a waste of time. Angelscript implements array and a map-like container, and I'm assuming I can use array like a list and just convert these types to their proper Irrlicht types with a function somewhere. This seems like a much easier way to do things. It could be laziness, but another solution I opted out of was the store the array subtype as a parameter, feed it to a wrapper so that I could cast the void pointer of the object to the type for returning an array...but, I think this will be safer.
  10. BrianEmpson

    Determining Template Subtype in Factory

    Thank you for clearing that up. So, I should create a wrapper class to deal with the instances of the array in the script, correct? I see in the scriptany add on that it's stored in a void* pointer but I do not quite understand what accounting needs to be done on the C++ side, especially if I need to transfer the array back and forth. (If I did need to do this, I would know the subtype beforehand as there aren't many instances where I would need to do this) So the factory would return a pointer to an object base that could handle storing the elements properly? Just trying to figure out the correct way to do this. This is new territory for me as I am not familiar with creating and using factories.
  11. Hello, I'm having trouble finding out what subtype is being used in my script templates when they are not primitive types, like an application class object, etc... Here is the registrations for the template: //The array type r = engine->RegisterObjectType("array<T>",0,asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0); //Factories and callbacks r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in)", asFUNCTIONPR(IrrArrayFactory, (asIObjectType*), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in, u32)", asFUNCTIONPR(IrrArrayFactory2, (asIObjectType*, u32), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in, const array<T> &in)", asFUNCTIONPR(IrrArrayFactory3, (asIObjectType*, const array<class T>), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in)", asFUNCTION(TemplateCallback), asCALL_CDECL); assert( r >= 0 ); //These are just to get the type to register properly for testing...I will implement a proper wrapper or something later r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_ADDREF, "void f()", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_RELEASE, "void f()", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(_NullFunc), asCALL_CDECL_OBJLAST); assert( r >= 0 ); //The factory function itself void IrrArrayFactory(asIObjectType *ot) //This is void for testing, later it will return an array { s32 typeId = ot->GetSubTypeId(); //s32 is just an int typedef stringc typeName = ot->GetName(); //stringc is my 8 bit char string class (in contrast to 16 bit stringw) cout<<"IrrArrayFactory()\n"; cout<<"Object: "<<typeName.c_str()<<" Type: "<<typeIdToStr(typeId)<<"\n"; return; } Because I do not know the template subtype yet, I can't instance an array<T> object yet. So I planned on doing something like this in the factory functions: switch (subtype) { case stringc: array *a = new array<stringc>(/* params */); case etc...: //continue for rest of defined types } But that's not too flexible...is there a way to find the type of the object in the application and dynamically instance a type in c++? Or am I going about this in the wrong way? As a side note, I wrote a function to find the subtype id name as such: char* typeIdToStr(u32 id) { cout<<"id was: "<<hex<<id<<" \n"; switch (id) { case asTYPEID_VOID: return "void"; case asTYPEID_BOOL: return "bool"; case asTYPEID_INT8: return "int8"; case asTYPEID_INT16: return "int16"; case asTYPEID_INT32: return "int32"; case asTYPEID_INT64: return "int64"; case asTYPEID_UINT8: return "uint8"; case asTYPEID_UINT16: return "uint16"; case asTYPEID_UINT32: return "uint32"; case asTYPEID_UINT64: return "uint64"; case asTYPEID_FLOAT: return "float"; case asTYPEID_DOUBLE: return "double"; case asTYPEID_OBJHANDLE: return "objhandle"; case asTYPEID_HANDLETOCONST: return "handletoconst"; case asTYPEID_MASK_OBJECT: return "mask_object"; case asTYPEID_APPOBJECT: return "appobject"; case asTYPEID_SCRIPTOBJECT: return "scriptobject"; case asTYPEID_TEMPLATE: return "template"; case asTYPEID_MASK_SEQNBR: return "mask_seqnbr"; default: return "unknown"; } } However, when executing the following script that makes an array of stringc's (an application registered string class), it returns: IrrArrayFactory() id was: 67108892 Object: array Type: unknown Test Script: print("Testing array object stuff...\n"); array<stringc> the_strings; //Don't actually do anything with it...there's no real factory yet... Does this indicate the the array subtype is invalid? It didn't throw an error like I would expect, nor is it any of the predefined values. (Note that this works fine for primitives): print("Testing array object stuff...\n"); array<u32> the_strings; Result: IrrArrayFactory() id was: 8 Object: array Type: uint32
  12. BrianEmpson

    AngelScript <-> C++ binder class.

    Let me know when templates are supported!! That's what I struggle with currently...
  13. BrianEmpson

    AngelScript <-> C++ binder class.

    I'll try this on my project (I'm binding a ton of 3d engine functions from "Irrlicht") and give you feedback
  14. BrianEmpson

    Basic Class Declaration in Multiple Files

    Thank you, I have fixed it after realizing the above problem...Now the code looks like this: //in main() r = config->builder.StartNewModule(config->engine, "scriptModule"); if( r < 0 ) { cout<<"Unrecoverable error while starting script module.\n"; //Should we exit here? } //Build function now builds all files in a list at once...in the same module void asBuildScripts() { s32 r; //r = builder.StartNewModule(config->engine, "scriptModule"); //config->mod = engine->GetModule("scriptModule"); for (u32 i=0;i<config->scriptList.size();i++) { r = config->builder.AddSectionFromFile(config->scriptList.c_str()); if( r < 0 ) { // The builder wasn't able to load the file. Maybe the file // has been removed, or the wrong name was given, or some // preprocessing commands are incorrectly written. cout<<"Error loading "<<config->scriptList<<".\n"; return; } //asBuildScript(config->scriptList.c_str()); } r = config->builder.BuildModule(); if( r < 0 ) { // An error occurred. Instruct the script writer to fix the // compilation errors that were listed in the output stream. cout<<"Please correct the errors in the script and try again.\n"; return; } return; } Thank you for all of the suggestions...I hope this setup works when I try to implement dynamic reloading of the scripts! More testing of that in the future!
  15. BrianEmpson

    Basic Class Declaration in Multiple Files

    They are loaded into the same module with the following code: //Prototypes for functions are above... int main() { //Snipped... asBuildScript(config->engine,"entity.as"); asBuildScript(config->engine,"main.as"); asRunFunc(config->engine,"void compile_scripts()"); asRunMethod(config->engine,"Entity","void Tick()"); asRunFunc(config->engine,"void main()"); //Snipped return 0; } void asBuildScript(asIScriptEngine *engine, std::string name) { u32 r; CScriptBuilder builder; r = builder.StartNewModule(engine, "scriptModule"); if( r < 0 ) { // If the code fails here it is usually because there // is no more memory to allocate the module cout<<"Unrecoverable error while starting a new module.\n"; return; } r = builder.AddSectionFromFile(name.c_str()); if( r < 0 ) { // The builder wasn't able to load the file. Maybe the file // has been removed, or the wrong name was given, or some // preprocessing commands are incorrectly written. cout<<"Please correct the errors in the script and try again.\n"; return; } r = builder.BuildModule(); if( r < 0 ) { // An error occurred. Instruct the script writer to fix the // compilation errors that were listed in the output stream. cout<<"Please correct the errors in the script and try again.\n"; return; } return; } void asRunFunc(asIScriptEngine *engine,std::string name) { u32 r; // Find the function that is to be called. asIScriptModule *mod = engine->GetModule("scriptModule"); int funcId = mod->GetFunctionIdByDecl(name.c_str()); if( funcId < 0) { // The function couldn't be found. Instruct the script writer // to include the expected function in the script. cout<<"Function " << name << " not found. Please add it and try again.\n"; return; } // Create our context, prepare it, and then execute asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(funcId); r = ctx->Execute(); if( r != asEXECUTION_FINISHED) { // The execution didn't complete as expected. Determine what happened. if( r == asEXECUTION_EXCEPTION) { // An exception occurred, let the script writer know what happened so it can be corrected. cout<<"An exception " << ctx->GetExceptionString() << " occurred. Please correct the code and try again.\n"; } } // Clean up ctx->Release(); return; } void asRunMethod(asIScriptEngine *engine,std::string object,std::string name) { asIScriptContext *ctx = engine->CreateContext(); // Get the object type asIScriptModule *module = engine->GetModule("scriptModule"); asIObjectType *type = engine->GetObjectTypeById(module->GetTypeIdByDecl(object.c_str())); if (type == 0) { cout<<"Error instancing class "<< object <<".\n"; return; } std::string decl = object + " @" + object + "()"; // Get the factory function id from the object type int factoryId = type->GetFactoryIdByDecl(decl.c_str()); // Prepare the context to call the factory function ctx->Prepare(factoryId); // Execute the call ctx->Execute(); // Get the object that was created asIScriptObject *obj = *(asIScriptObject**)ctx->GetAddressOfReturnValue(); if (obj == 0) { cout<<"Unable to get object return value for " << object << ".\n"; return; } // If you're going to store the object you must increase the reference, // otherwise it will be destroyed when the context is reused or destroyed. obj->AddRef(); // Obtain the id of the class method int funcId = type->GetMethodIdByDecl(name.c_str()); // Prepare the context for calling the method ctx->Prepare(funcId); // Set the object pointer ctx->SetObject(obj); // Execute the call ctx->Execute(); return; } I will try the add script section code...
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!