Game Development Community

Running out of object id numbers

by Lee Latham · in Torque Game Engine · 02/12/2008 (2:00 pm) · 35 replies

Okay, this is kinda embarassing but here goes:

Is it possible to run out of object id numbers? I'm not even sure if I have the right terminology. What is the right term for those on the server side?

Reason I ask is I'm running into issues when I have my dedicated server up for a long time. I have some items, like a jetpack that generates a LOT of particles, each with their own unique id number, that go through those pretty darn fast.

So I'm wondering if there is a limit, say a 32 bit float or something, that I could be hitting that could be causing a crash? Is there a way to "reset" this?

Or am I just chasing phantoms?
Page«First 1 2 Next»
#21
02/15/2008 (8:24 pm)
I'm not sure if I've ever run my IDs up even that high, so I don't really know what happens.. but I don't think an int->string->int conversion would cause a problem. Mathematical operations cause problems because the compiler seems to convert everything to floats. Look for OP_ADD in compiledEval.cc. It only knows one "add" operation and it assumes floats.

... Further looking at compiledEval.cc it seems int->string uses sprintf(%d) and string->int uses atoi. String to int conversions should work fine. (Search for OP_UINT_TO_STR and vise versa.) Ironically, while TorqueScript calls its integer type "UInt" presumably for "Unsigned Integer", they're really signed integers being returned as unsigned integers. Which is stupid and a waste, but not relevant to your current issue.

I still think your problem is not what it seems.
#22
02/16/2008 (4:48 am)
For what it's worth, I ran a quick test in my game to push IDs up past one million and saw no problems. I wrote
function foo(%n)
{
	for (%i = 0; %i < %n; %i++)
	{
		%p = new Projectile()
		{
			dataBlock = "Spaz";
		};
		%p.delete();
	}
	
}
Then called foo(999999) after loading a mission. No errors occurred. I then opened the World Editor and shot some new projectiles to confirm that they were indeed using SimIDs greater than 1 million. They were, quite happily.

Granted, the specifics of your engine and scripts are different. This does establish however that as of version 1.3 Torque could handle simple script-generated objects with large IDs. You might want to run a similar test in your game to establish if large IDs are indeed the cause of your trouble.
#23
02/16/2008 (7:00 am)
I think you're on the wrong track Lee. Those script functions shouldn't crash the engine if you give them incorrect object ID's, I think I've tried that once or twice.

If however the issue *is* script related, you can easily avoid it (but not solve it!) by moving the relevant code into engine code. Took me an hour or so to get all the game.cs related functionality into GameConnection. It's not addon/script friendly but it'll solve script big-number issues like the ones described in the other threads.

Gotta go.
#24
02/16/2008 (2:13 pm)
Well this is damn interesting.

For what it's worth, I checked my stock TGE 1.5.2 install and it still has the simple math errors when you try to use numbers 1000000 and above, which surely is related somehow, if indirectly.

However, I took Scott's function (thanks good idea!) and duplicated his results--sure enough, I can create new projectiles just fine above one million.

So now I understand the problem better. The problem is not creating simID's above one million. In fact, it's obvious now in retrospect, because my AI players had the simID's above one million, but it's just the scripts broke.

The problem is that my scripts are getting fed exponents when the simID is above one million.

Ah, but not ALL of my scripts! Armor::onDamage and VehicleData::onDamage, for example, are getting fed the supra-one million numbers just fine, it's just my own AIPlayer::notMoving function that is getting the exponents. This is a simple function that checks to see if an aiplayer is stuck every several seconds.

Could this be an issue on the AIPlayer source side of life? I'm struggling to grasp where this could have come in. I'm not doing any script side math on the simID numbers...I mean, why would I?
#25
02/16/2008 (2:37 pm)
A curious problem this is. It does look like the problem starts after IDs have exceeded the 1 million mark.. But it can't be that simple. Also interesting is the fact that it occurs on a mission change. Does it always happen after loading a new mission? What happens if you use the loop I posted to kick the IDs up beyond a million.. Does it break straight away? Or not until you start a new mission?

Can you post some of your aiPlayer.cs? Like around line 596?
#26
02/16/2008 (6:24 pm)
No, it has no bearing on loading the mission--it just happened to fail at that point in that log.

Using your function I can make it happen at any time, straight away, without loading a new mission. However, I think maybe we're getting to the bottom of things. Here's the function in question (in it's entirety just so you can see that I'm not leaving out anything important):

function AIPlayer::notMoving (%player,%pos)
{
   if (%player.getControlObject() $= "0" ){
      %player.schedule(5000,"notMoving",%place);
   return;
   }

  %place=%player.getControlObject().getWorldBoxCenter(); 
  
  %place0 = getWord(%place, 0);
  %place1 = getWord(%place, 1);
  %place2 = getWord(%place, 2);
  
  %place = %place0 + %place1 + %place2;
  %thiscar = %player.getControlObject();

if (mAbs(%place - %pos) < 0.5){
   %player.getControlObject().damage(%player, %player.getPosition(), 2000, "M16Ammo");
   return;
}
  
    %player.schedule(5000,"notMoving",%place);
}

The intention of the function is to simply roughly determine if the AI's (driving wheeled vehicles) haven't moved in the previous five seconds, and if so, kill them.

It is called when the AIPlayer is created with:
AIPlayer::notMoving (%player,0);

in the player spawn function, where %player is the player object (a DemoPlayer who mounts a vehicle shortly after spawning).

So I was looking at this and remembering that I don't really grok the whole namespace concept in Torque--that is, many times they don't work like I think they should but I don't spend time worrying about it, I just nuke the namespace in the function name. So just now I tried renaming my notMoving function to just plain "notMoving", and getting rid of the AIPlayer:: prefix.

That's when something interesting happened. You see the IF statement at the beginning of the function where I check to see if the AIPlayer has a controlobject? Well, when I remove the AIPlayer:: prefix, it always returns 0, and then for some reason the function is never called again after the first time! I stick a breakpoint in there and it is only tripped when the AI's spawn or respawn, and the schedule's never take effect.

Hmm, I'm sticking my spawn function below. I suspect the problem must lie there, particularly since there are parts that I only barely understand:

function AIPlayer::spawn(%name, %obj)
{

  %ai = createAIBot(%name); //this runs a little function that does %ai = aiConnect(%name); return %ai
   
   %milly=512;

   %player = new AIPlayer() {
   dataBlock = DemoPlayer;

   isbot=true;
   fireevery=%milly;
   client=%ai;
   marker=%obj;

   fov=$AI_PLAYER_FOV;
   attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
      

   marker = %obj;
   

   path = %obj.pathname;
   botname = %name;
   
   };
   MissionCleanup.add(%player);
   %ai.isbot = 1;
   
 
   if (%obj.respawn $= "" )
   	{
   		%player.respawn=$AI_PLAYER_DEFAULTRESPAWN;
   	}
   	else
   	{
   		if (%obj.respawn == true)
   			%player.respawn=true;
   		else
   			%player.respawn=false;
   	}
 	 
 	
 	 %player.EquipBot(%player);  
   
   %player.setShapeName(%name);
   %player.setTransform(%obj.gettransform());
   %player.followPath(%obj.pathname,-1);


AIPlayer::notMoving (%player,0);

   return %player;
}
#27
02/16/2008 (6:57 pm)
Quote:That's when something interesting happened. You see the IF statement at the beginning of the function where I check to see if the AIPlayer has a controlobject? Well, when I remove the AIPlayer:: prefix, it always returns 0, and then for some reason the function is never called again...

Just real quick here.. By calling %player.schedule("notMoving") you're telling Torque to look for a function "notMoving" in the class to which %player belongs. Presumably %player is of type AIPlayer, so you'll need a function AIPlayer::notMoving. There is a slightly different syntax (which I don't recall offhand) for scheduling a function in the global namespace. Might be as simple as leaving off "%player" but I'm not sure. Anyway, if you remove "AIPlayer::" Torque cannot find the notMoving function and no schedule is created.

Now to continue reading your previous post...
#28
02/16/2008 (7:22 pm)
First thing that jumps out is the name of the function AIPlayer::spawn(). In this case spawn() doesn't seem to make sense as a function of AIPlayer since you have yet to create an AIPlayer instance. Still.. it should work if you call it directly with "AIPlayer::spawn(name,obj)".. Meh. moving on..

This still confuses me.. Your log file reads "Unable to find object: '1.00021e+006' attempting to call function 'setImageTrigger'".. Where is this 'setImageTrigger' function that it's trying to call? I don't see that in the code you posted? Which line above is line 596 exactly?

Perhaps more importantly, what is the first error message you receive after the IDs get past 1 mil?
#29
02/16/2008 (7:39 pm)
Hmm. This line also is worrying me..
%player.EquipBot(%player);

Partly because %player need not be in there twice; Partly because I'm speculating that setImageTrigger could be called as a result of equipping a weapon.

If you have a function in a "class" (as AIPlayer::EquipBot), when you call that function on an instance of the class (as %player.EquipBot) the first parameter passed to that function will be a "pointer" to the instance on which the function was called. Ergo you want your function definition to look rather like this
function AIPlayer::EquipBot(%this, %firstArg, %secondArg, %etc)
{
   // %this is the %player on which EquipBot was called
}

// Call above function thusly
%player.EquipBot(%firstArg, %secondArg, %etc);

In C++ any member function inherently has a "this" variable that is a pointer to the instance the function is called on. TorqueScript simulates that by passing "this" as the first argument to a "member" function.

I don't know that that's the cause of your trouble, but it may be worth noting.
#30
02/16/2008 (7:43 pm)
Also...

If you echo(%player) after you create a new AIPlayer thusly
%player = new AIPlayer() {
   dataBlock = DemoPlayer;

   isbot=true;
   fireevery=%milly;
   client=%ai;
   marker=%obj;

   fov=$AI_PLAYER_FOV;
   attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
      

   marker = %obj;
   

   path = %obj.pathname;
   botname = %name;
   
   };
   [b]echo(%player);[/b]

You'll see if the new player ID looks valid at that point. Might be useful to note.

.. Ok that's all I've got for now. :P
#31
02/16/2008 (9:42 pm)
Hmmmm, I think we're getting closer, here. But first, to reply to your thoughts in order:

I thought doing %player.schedule (stuff) was identical to schedule (%player)? That it is just TorqueScript being "flexible"? I did change it up and didn't see any difference, btw.

On the setImageTrigger thing, I have to apologize. I let the server run for 24 hours on my old version (because I knew the problem happened there), where I also had a random fire command, very very similar to the notMoving one. I've taken out the random fire one for other reasons, but the notMoving one has identical issues, which I'll get on to in a moment.

On the equipBot thing, frankly I'm not sure how that got there! I think that was in the default AIPlayer.cs I got, and I don't think it really does anything for me to speak of, actually. But you're right, even I know that's not right. I'll be checking it out. But I think I've found some more important information.

I liked your idea of echo'ing stuff out, so I planted them all over the place. What's really interesting is that I put one at the beginning of notMoving, and after running up the simID's I got this:
notmoving 1002292
singularity/server/scripts/aiPlayer.cs (620): Unable to find object: '1.00228e+006' attempting to call function 'getWorldBoxCenter'
singularity/server/scripts/aiPlayer.cs (635): Unable to find object: '1.00228e+006' attempting to call function 'Damage'
So the simID is being passed to my function just fine! A little more echoing and stepping through verifies that it is getControlObject which is returning the exponent, and jacking up the rest of the function!
#32
02/16/2008 (10:09 pm)
Bingo! Check out the ConsoleMethod for Player::getControlObject (player.cc, line 3691 in my version)
ConsoleMethod( Player, getControlObject, F32, 2, 2, "Get the current control object.")
{
   ShapeBase* controlObject = object->getControlObject();
   return controlObject? controlObject->getId(): 0;
}

It returns a friggin Float type! What the #$%&?! Well that's wrong. Change it to
ConsoleMethod( Player, getControlObject, [b]S32[/b], 2, 2, "Get the current control object.")
{
   ShapeBase* controlObject = object->getControlObject();
   return controlObject? controlObject->getId(): 0;
}
Problem solved!
#33
02/16/2008 (10:38 pm)
Quote:I thought doing %player.schedule (stuff) was identical to schedule (%player)?

Just to follow up... Two ways to write it:

object.schedule(time, functionName, arguments);
will call:
ObjectClass::functionName(this, arguments)

or

schedule(time, 0, functionName, arguments);
will call:
functionName(arguments)

Additional note: The documentation says that schedule takes as its second arguments an "object or 0", yet there's little point to passing it an object as it will not be passed along to the scheduled function. Go figure.

You could of course pass along an object "pointer" yourself as an argument.
#34
02/17/2008 (12:03 am)
That worked! Thanks, Scott--I'd gone in there and poked around, but I was still too ignorant to spot the problem. I really appreciate your help! And you other guys, too!

Thanks for the clarification on schedule, too. I got it. Although I use schedule quite heavily, it still did have some mysteries for me.
#35
02/17/2008 (12:05 am)
Quote:
Additional note: The documentation says that schedule takes as its second arguments an "object or 0", yet there's little point to passing it an object as it will not be passed along to the scheduled function. Go figure.

The second parameter is not an argument to be passed, it's the object id of a "reference object". The reason for passing a (valid) objectID is in the scenario where if that object gets deleted before the event fires, you want the event deleted as well.
Page«First 1 2 Next»