Using the CScriptHandle between C++ and Angelscript

Started by
2 comments, last by WitchLord 12 years, 6 months ago
Are the there any examples of this? I wanted to use it as a vehicle for user data for my messaging system, but the problem is that after it's gone between Angelscript to the C++ side, casting it back to toe required type in Angelscript results in a null pointer.

Here is a basic overview of the system.





#pragma once
#ifndef IR_MESSAGE_DISPATCHER_H
#define IR_MESSAGE_DISPATCHER_H

#include <set>

#include "Object.h"
#include "../script/angel/scripthandle.h"


#undef DispatchMessage

namespace Irre {


struct Telegram
{
Telegram( double delay,
asIScriptObject* sender,
asIScriptObject* receiver,
int message,
CScriptHandle& data )
: Sender( sender ),
Receiver( receiver ),
Message( message ),
DispatchTime( delay ),
Data( data )
{
Sender->AddRef();
Receiver->AddRef();
}

~Telegram()
{
Sender->Release();
Receiver->Release();
}

asIScriptObject* Sender;
asIScriptObject* Receiver;
int Message;
double DispatchTime;
CScriptHandle Data;

bool operator<=( const Telegram& other ) { return DispatchTime <= other.DispatchTime; }
bool operator==( const Telegram& other ) { return DispatchTime == other.DispatchTime; }
};

class MessageDispatcher
{
public:
void TransmitMessage( double delay,
Object* sender,
Object* receiver,
int msg,
CScriptHandle& data );

void DispatchDelayedMessages();

private:
void Discharge(Object* receiver,const Telegram& message);

std::set<Telegram> m_DelayedTelegrams;
};

}
#endif



#include "MessageDispatcher.h"
#include "../shared/Global.h"
#include "../script/angel/ScriptFunctions.h"
#include "Stage.h"
#include "ObjectManager.h"
#include "Engine.h"

namespace Irre {

void MessageDispatcher::TransmitMessage( double delay,
Object* sender,
Object* receiver,
int msg,
CScriptHandle& data)
{
float current_time = IR_GetTick();
Telegram message(0,sender->m_Core,receiver->m_Core,msg,data );

if( delay == 0 ) Discharge( receiver, message );
}

void MessageDispatcher::Discharge( Object* receiver,const Telegram& message )
{
receiver->ReceiveMessage( message );
}

void MessageDispatcher::DispatchDelayedMessages()
{
// Not implemented yet.
}

}



void RegisterDispatchMessage( asIScripeEngine* e )
{
// Registering the global function.

r=e->RegisterGlobalFunction("void IR_DispatchMessage(double,int,int,int,ref&in)", asFUNCTION(IR_DispatchMessage), asCALL_CDECL); AS_CHECK(r);
}


/* Dummy */
void TelegramDummy( Telegram* self ) { }
void TelegramDestructor( Telegram* self )
{
((Telegram*)self)->~Telegram();
}


void RegisterTelegram( asIScriptEngine* e )
{

r=e->RegisterObjectType("Telegram",sizeof(Telegram),asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CD );AS_CHECK(r);

r=e->RegisterObjectBehaviour("Telegram",asBEHAVE_CONSTRUCT,"void f()",asFUNCTION(TelegramDummy),asCALL_CDECL_OBJLAST);AS_CHECK(r);
r=e->RegisterObjectBehaviour("Telegram",asBEHAVE_DESTRUCT,"void f()",asFUNCTION(TelegramDestructor),asCALL_CDECL_OBJLAST);AS_CHECK(r);
r=e->RegisterObjectProperty("Telegram","IObject@ Sender",offsetof(Telegram,Sender));
r=e->RegisterObjectProperty("Telegram","IObject@ Receiver",offsetof(Telegram,Receiver));
r=e->RegisterObjectProperty("Telegram","int Message",offsetof(Telegram,Message));
r=e->RegisterObjectProperty("Telegram","double DispatchTime",offsetof(Telegram,DispatchTime));
r=e->RegisterObjectProperty("Telegram","ref@ Data",offsetof(Telegram,Data));
}






void OnMessageReceived( const Telegram&in message )
{
switch( message.Message )
{
case TA_Messages::BODY_WITHIN_RADAR_RANGE:
{
TA_Body@ sensed_body = cast<TA_Body@>(message.Data); // The data is null when it gets passed to IsFriendly.
if( sensed_body is null ) Println("The sensed body was null for whatever reason.");

if( !IsFriendly(sensed_body) && !IsDead )
{
m_SensoryMemory.SaveMemoryEntry( TA_MemoryRecord(sensed_body.TA_Mind,sensed_body.Position) );
}
} break;
case TA_Messages::AGENT_ORDER_DROP_EVERYTHING:
case TA_Messages::AGENT_ORDER_PATROL:
case TA_Messages::AGENT_ORDER_WEAPONS_FREE:
case TA_Messages::AGENT_ORDER_DEFEND:
case TA_Messages::AGENT_ORDER_SEEK_AND_DESTROY:
{
DispatchMessage( 0,m_ThinkGoal,message.Message,message.Data );
} break;
}


By the way, I know for a fact that the data that gets passed to the telegram in the first place is guaranteed to not be null. And yes, I am well aware of interfaces and such, but I find messaging to be much more convenient than using interfaces for everything. I have also tried using a pointer to the CScriptHandle, but that eventually leads to either a segfault or an assertion.
Advertisement
Hmm. Have you tried setting a break point in the CScriptHandle::opCast method to see what is going on?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

It actually seems to be a problem with handles being held in a value type. When I register the telegram as a reference type, the data remains intact.
You've registered your Telegram type as a POD object, but it is not. asOBJ_POD tells AngelScript that it is allowed to make bitwise copies of the object, which will cause havok if the object has handles as members (it won't update the ref count properly).

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement