Jump to content

UserData C++


smashthewindow
 Share

Recommended Posts

Okay, I need some help in C++...

I'm just a hobby programmer so I'm not that good.

 

I've a basic class called "Object", and every class I made inherits from that object:

class Object {
public:
	TEntity _entity;
	TVec3	_abspos;

	Object( TEntity entity_ = NULL ) {
		if( entity_ != NULL ) {
			_abspos = EntityPosition( entity_, 1 );
			FreeEntity(entity_);
		}
		_entity = CreatePivot();
		SetEntityUserData( _entity, (byte*)this ); //take notice in this part...
		HideEntity(_entity);
	}
};

and of the callback function:

void _stdcall UpdateControllerCallback( TEntity entity ) {
	Controller* e = (Controller*)GetEntityUserData(entity);
	e->UpdateBall();
}

      void Controller::UpdateBall() {	
	PositionEntity( _campivot, EntityPosition(_ballmesh,1) );
}

Of course, controller inherits from Object class and yes, Object's constructor is called.

 

But that PositionEntity() throws an exception if I run it at VS2010 (_campivot is a bad pointer...)

I know this is noob question, but I can't figure it out after hours of searching.

Can anyone help me?

 

EDIT: Basically, I'm asking if anyone knows what the hell is wrong with UserData setting/retrieving...

The pointer I get from GetUserData() func seems to be +4 bits from the original location.

I'm using Leadwerks 2.5 by the way, straight from the Updator.

Blog & Portfolio

 

Current project: moon.chase.star

Link to comment
Share on other sites

So you are stepping through this and e->UpdateBall() makes it into your Controller::UpdateBall() and you are seeing _campivot as a bad pointer is that right?

 

I don't see where _campivot is being created in your code above. Also not seeing where the callback is setup above. Can you show that. Also I assume you are creating a pointer to Controller like:

 

Object* obj1 = new Controller(); ??

Link to comment
Share on other sites

So you are stepping through this and e->UpdateBall() makes it into your Controller::UpdateBall() and you are seeing _campivot as a bad pointer is that right?

 

I don't see where _campivot is being created in your code above. Also not seeing where the callback is setup above. Can you show that. Also I assume you are creating a pointer to Controller like:

 

Object* obj1 = new Controller(); ??

 

	Controller( TEntity entity_ = NULL ) {
		Ball::Ball(entity_);

		//set mesh of the ball
		SetMesh("abstract::ball_ball1.gmf");

		_campivot = CreatePivot();
		_camposition = CreatePivot(_campivot);
		PositionEntity( _camposition, Vec3(0,0,-5) );

		//control variables
		camrotation=Vec3(0); 
		cam2rotation=Vec3(0);
		mx=0; 
		my=0; 
		move=0; 
		strafe=0; 
		jump=20;

		SetEntityCallback( _entity, (byte*)UpdateControllerCallback, ENTITYCALLBACK_UPDATE );
	}

 

That's my constructor.

Object->Ball->Controller, this is the class inheritance structure.

Everything else I've implemented is working except for the accessing userdata part.

 

Object* obj1 = new Controller(); ??

 

and no. I loop through entities in a map and search for the entity with key "ball_controller". From there I call

Controller my_awesome_controller_instance(found_map_entity);

 

basically a while() & for() loop like they do it in GameLib.

Thank you for replying anyways.

Blog & Portfolio

 

Current project: moon.chase.star

Link to comment
Share on other sites

Can we see that scene loading code you have? The way you create your Controller object sort of looks like it would go out of scope once the scene loading is finished which means the class would get deleted. Normally unless you have global variables you would want to use pointers so as to keep the objects you create "alive" for the long haul (past the method they were created in).

Link to comment
Share on other sites

void Scene::LoadMap( string mapname ) {
	_mapname = mapname;
	_scene = LoadScene(mapname.c_str());

	_camera = GetLayerCamera( GetFrameworkLayer(0) );        
	PositionEntity( _camera, Vec3(0,0,-2) ); 

	ProcessMapInfo();
	ProcessMap();
}

void Scene::ProcessMapInfo() {
}

void Scene::ProcessMap() {
	if(!_scene)return;
	TEntity e=NULL;
	int i=0;
	int done=0;
	int childs=0;
	string tp="";
	string en="";
	string em="";
	string ct="";	// collision type, used for collision with static objects
	while(!done) {
		done=1;
		childs = CountChildren(_scene);
		for(i=1;i<=childs;i++) {
			e=GetChild(_scene,i);
			tp=GetEntityKey(e,"Type");
			en=GetEntityKey(e,"Name");
			em=GetEntityKey(e,"Mass","");
			ct=GetEntityKey(e,"CollisionType","");

			if( tp == "info_ball_node" ) {
				Controller newcont(e);
				//newcont.SetCamera(_camera);
				done=0;
				break;
			}
		}
	}
}

 

shouldn't be a problem as there is break; before the closing braket of if (this is how gamelib does it.)

gives the same results even if I use the global instances.

Blog & Portfolio

 

Current project: moon.chase.star

Link to comment
Share on other sites

That doesn't seem right. Controller newcont object should delete itself after that if statement because those brackets define the scope that object is in. Even if the break did something the object would only live until ProcessMap completed, meaning anything after ProcessMap newcont doesn't exist anymore.

 

Do you have a destructor for your Controller class? Put a breakpoint in there and as you step through see when it gets called because to me that looks like that object wouldn't survive past either that if statement or the function. Which means inside the ctor you are storing off the address of the object to LE. After the object is destroyed LE still has that memory address stored. Then you convert that back to the class instance but that memory space could be anything by then. It surprises me that e->UpdateBall() doesn't fail on the call itself though.

 

gamelib might be doing something slightly tricky as Lum is known to do funky things :)

 

 

 

gives the same results even if I use the global instances.

 

That seems odd too. What did you do exactly to actually make it a global instance? Without making it a pointer you can't have it global and pass that data in that function to the ctor because if it's not a pointer to ctor gets called right away, which wouldn't work if you made it global because that would mean you defined it right away but you couldn't have passed it anything to it's ctor because you can't until you are in the process function.

 

In Scene header file try:

 

Controller* newcont;

 

Then in the if statement in process scene do newcont = new Controller(e); See if that works. That will make that object live until you deleted it, which you should in the scene object destructor. Then as long as the Scene object is alive (which I assume stays alive through your game. if it doesn't then you have another issue), your controller object will stay in memory too.

Link to comment
Share on other sites

Several things:

 

Firstly,

 

Do I presume that there is a

 

typedef unsigned char byte;

somewhere at the top of the code?

 

When you set the entity's UserData, take out the (byte *) bit, any type of pointer is valid. You only have to cast it to the correct type when you are retrieving it

 

SetEntityUserData( _entity, this );

 

I wouldn't have thought it was very likely, but maybe the cast to byte is causing an error. You could try comparing (or printing out to the console) the value of this and (byte *) this.

 

std::cout << "pointers " << ((this != (byte *) this)? "don't" : "") << " match\n";
if(this != (byte *) this)
   std::cout << (int)this << "  |  " << (int)(byte *) this << "\n";

 

 

Secondly,

 

I also didn't think that was the correct way to call an inherited constructor. That's the Java way, and I'm sure things didn't work when I first tried that in C++. Check this page (under the subtitle "What is inherited from the base class?"):

 

http://www.cplusplus.com/doc/tutorial/inheritance/

 

In your case, rather than:

                Controller( TEntity entity_ = NULL ) {
                       Ball::Ball(entity_);

                       //The rest of your Controller constructor is unmodified
               }

 

It would look like

                Controller( TEntity entity_ = NULL ) : Object( entity_) // Notice what's been added here... A colon and a constructor call
               {
                       //Ball::Ball(entity_); //Not here, notice it's gone green in your compiler...

                       //The rest of your Controller constructor is unmodified
               }

 

this assumes that your code above is in the class declaration. The added bit can only go inside a class block. For example, what I've done below, I believe isn't allowed.

 

class Controller : public Object
{
public:
   Controller( TEntity entity_ = NULL );
};

Controller::Controller( TEntity entity_) : Object( entity_)
{
   //blah blah
}
//Not valid

 

class Controller : public Object
{
public:
   Controller( TEntity entity_ = NULL ) : Object( entity_) ;
};

Controller::Controller( TEntity entity_ = NULL )
{
   //blah blah
}
//Valid

 

class Controller : public Object
{
public:
   Controller( TEntity entity_ = NULL ) : Object( entity_)
   {
       //blah blah
   }
};
//Valid

LE Version: 2.50 (Eventually)

Link to comment
Share on other sites

Thanks for all your help, Mumble and Rick.

I still havent figured out my problem, but I've tested the following code on a sample project, Get/SetUserData seems to be working fine.

Maybe it's just time for me to rewrite some stuff.

 

Fixed the problem:

This is my class layout:

 

Object->Ball->Controller

 

I have a virtual function in Ball & Controller (its called GetBallType(), returns int )

I removed the virtual function, everything's working perfect and all. (I were thinking somethinking like pointer alignment because the address I got from GetUserData was always 4 bits off from the original place - maybe the vtable pointers got messed up.)

Can I ask why it maybe causing problems like that?

Blog & Portfolio

 

Current project: moon.chase.star

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...