Advertisement

Problems with exposing a class as global

Started by July 06, 2007 02:27 PM
10 comments, last by _Sigma 17 years, 4 months ago
I am trying to expose a basic input query system to AS for use from scripts. This would allow one to poll if a key was down, etc. I would like to register the class so that no instances or handles can be created/used. I'm having problems what the final pointer should be in the call to RegisterGlobalProperty. It is either an asUptr or void*. My code looks like thus:

//set up input
	m_script.RegisterObject("TInput");
	m_script.RegisterObjectMethod("TInput","bool IsKeyDown(string key)",asMETHOD(TInput,IsKeyDown));
	m_script.RegisterAsGlobal("TInput Input",(void*)m_input);

The first 2 functions work(used elsewhere) and I'm quite certain RegisterAsGlobal is fine, but just in case, RegisterAsGlobal is like thus:

void TScript::RegisterAsGlobal( std::string declaration, void* ptr )
{
	if(ptr)
	{
		int r = m_engine->RegisterGlobalProperty(declaration.c_str(),ptr);
		r < 0 ? throw TFatalException("Failed to register global property" + declaration + " with Angel Script. \n\n In:\n TScript::RegisterGloalProperty") : ++r;
	}
	else
	{
		throw TFatalException("Failed to register global property " + declaration + " with Angel Script. Reason: Void function pointer. \n\n In:\n TScript::RegisterGloalProperty");
	}
}

In the preceeding code, m_input is a TInput instance (TInput* actually). When I try this code from a script,
 

					  Input.IsKeyDown("T_Left");
					  
					  if(Input.IsKeyDown("T_Left") == true)
					  {
					  	LeftDown();
					  }
The call into IsKeyDown is made, but it crashes with strange unhandled exception errors when I try working with iterators. If I call the code from my main C++ game loop everything works just peachy! Cheers
asUptr is only used for function and method pointers. You should pass the address of the actual object to RegisterGlobalProperty.

Take a look at the source for tests/test_feature/source/test_objzerosize.cpp. That's the tests I make for registering objects that cannot be instantiated in the script.

That code permits the use of object handles, but it should just be a matter of not registering the ADDREF and RELEASE behaviours to disallow that.

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
Quote: You should pass the address of the actual object to RegisterGlobalProperty.

So what I'm doing is correct then?
m_script.RegisterAsGlobal("TInput Input",(void*)&m_input);

No, you should have used &m_input and not m_input.
Also change your register function then to:

void TScript::RegisterAsGlobal( std::string declaration, void* ptr ){	if(ptr && *ptr)	{		int r = m_engine->RegisterGlobalProperty(declaration.c_str(),ptr);		r < 0 ? throw TFatalException("Failed to register global property" + declaration + " with Angel Script. \n\n In:\n TScript::RegisterGloalProperty") : ++r;	}	else	{		throw TFatalException("Failed to register global property " + declaration + " with Angel Script. Reason: Void function pointer. \n\n In:\n TScript::RegisterGloalProperty");	}}
Quote: Original post by midnite
Also change your register function then to:

*** Source Snippet Removed ***

error C2100: illegal indirection

Quote:
No, you should have used &m_input and not m_input.

Sorry, I was brutally jet lagged when I wrote that (and still am a little). So if I have
TInput* input = new TInput;
, why do I want the address of the input ptr? Didn't I want just the pointer to the TInput object cast to void*?

Something is very bizzare on my end. When I try a simple little test class(pointer and otherwise), I can register it as a global, call all of its properties, methods, etc just fine. Yet when I try a pointer to a TInput instance, I get an exceptions out the wazoo (C-Runtime - not my own). When I try creating a non-pointer instance (I feel dumb, what is that techincally called?), I get the strangest debug assert:
---------------------------Microsoft Visual C++ Debug Library---------------------------Debug Error!Program: ...Module: ...is\My Documents\Programming\C++\Tempest\bin\Debug\Tempest.exeFile: c:\documents and settings\chris\my documents\programming\c++\tempest\code base\working source\angelscript_2.8.0a\source\as_callfunc_x86.cppLine: 1023Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.(Press Retry to debug the application)---------------------------Abort   Retry   Ignore   ---------------------------

I am using asCALL_THISCALL for all the method registrations (x86 windows xp2).
Depending on the mood of my computer, I also get the general assert of "...your program just died."

Any ideas as to what I can check?
Advertisement
Something like the following code should work. Make sure you register in AngelScript after you allocate your m_input...


class TInput{  TInput()  {   ...  }  ~TInput()  {   ...  }  bool IsKeyDown( const char *key )  {   ...  }  // script version, to handle the AngelScript string input  bool IsKeyDownScript(const asCScriptString *key)  {    return IsKeyDown( key->buffer.c_str() );  }  // return the singleton  static TInput &Get(void)  {   if( m_input == NULL )   {     m_input = new TInput;   }   return *m_input;  }  // register the class with AngelScript  static bool Register(asIScriptEngine *engine)  {    // register    if( engine->RegisterObjectType( "TInput", 0, asOBJ_CLASS_C ) < 0 ) return false;    if( engine->RegisterGlobalProperty( "TInput Input", &Get() ) < 0 ) return false;    if( engine->RegisterObjectMethod( "TInput", "bool IsKeyDown(const string &in)", asMETHOD(TInput,IsKeyDownScript), asCALL_THISCALL ) < 0 ) return false;    return true;  }  static TInput *m_input;}// our singletonTInput *TInput::m_input = NULL;



And then, somewhere in your code:
...TInput::Register( engine );...


If you wanted to use your input code in C++ code:
...bool isDown = TInput::Get().IsKeyDown("T_Left");...
I've double checked that the TInput instance is being initialized before being registerd. I changed the IsKeyDown to just return false so I could narrow the problem down.

I can now consistently get this error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

This is right after AS properly calls into IsKeyDown (in the TInput instance). It is when it returns that the assert is raised.
So I'm at a total loss for what is wrong. I have a test class that works just fine, yet another very similar class does not...Any ideas?
Did you try registering like how I wrote the code? How did you write your IsKeyDown function? You need to register it as:

"bool IsKeyDown(const string ∈)"

and in C++ it should be

bool TInput::IsKeyDown(const asCScriptString *str)

or

bool TInput::IsKeyDown(const asCScriptString &str)
Quote: Original post by midnite
Did you try registering like how I wrote the code? How did you write your IsKeyDown function? You need to register it as:

"bool IsKeyDown(const string ∈)"

and in C++ it should be

bool TInput::IsKeyDown(const asCScriptString *str)

or

bool TInput::IsKeyDown(const asCScriptString &str)

W-T-F. why does that make it work1!!??? Becuase that did solve the problem! O_o.

This topic is closed to new replies.

Advertisement