Game Development Community

Object IDs don't reset after disconnecting?

by Chad Hall · in Torque 3D Beginner · 04/23/2013 (7:38 am) · 30 replies

I'm working on a single player game and awhile back I designed a saving/loading system. I'm noticing now when I load games my object IDs get larger instead of going back to what they were when the program is first started. For example, when I first enter a game my player ID is 4216. Then I load from a save and my player ID is 4322. Do it again and my player ID is 4479, etc.

The same thing happens when exiting the game properly (exiting to the main menu and loading the map again.). This happens both in my game and in an unmodified copy of T3D 2.0 so it appears to be a function in the engine itself rather than something I did. Should I be concerned about this? Once I get to a point where I'm adding way more objects and players will potentially load game saves or change levels won't they eventually hit a limit?
Page «Previous 1 2
#1
04/23/2013 (8:44 am)
That is a great find. I started to see a large growth in the automated numbers when creating new gui elements. A simple text control is now around the 12000 mark. I am not sure if this issue applies to gui elements when they are loaded into the game, but it started to concern me since I am making an RPG which will have a lot of gui's.
#2
04/23/2013 (8:59 am)
I guess you might see an issue when you hit id number 2^32 (or 2^31 if torque is using S32 for the id's)
#3
04/23/2013 (9:10 am)
Should this be happening, though? It seems to me the IDs should be cleared once the server is destroyed to avoid any issues. I don't really see any reason you'd need to keep adding to the last biggest ID number once those IDs are no longer in use.
#4
04/23/2013 (9:48 am)
Yes, T3D does not recycle ID's as far as I'm aware, they just creep upward. On a plus side, the cap is a REAL Big number.

Unfortunately I can't tell you which is the cap 2^32 or 2^16 because half the engine is coded w/ the id being a S32 and the other half of the engine is coded w/ it being a U32.

It's one of those things that needs to be fixed by MIT.
#5
04/23/2013 (11:39 am)
@Vince,
I have to wonder about your maths here:
2^32 is a 32 bit unsigned int max value
2^31 is a 32 bit signed int max value

If it is going to be a problem it might be a good idea to find out:
// max value test
function testIds(){
  %max = 2147483648;  // 2^31, may need to try 2^32
  %printmax = 100000;
  %loopmax = %max / %printmax;
  for(%i=0; %i<%loopmax; %i++){
    for(%j=0; %j<%printmax; %j++){
      %obj = new SimObject();
      %obj.delete();
    }

    echo(%obj);
  }
}
testIds();
echo("done");
Or similar code to test maximum behavior.

Edit:
Fixed logic errors and am running the code now. Will take a while...
#6
04/23/2013 (1:19 pm)
I played around for awhile to see what would happen if I altered the ID setting to fill empty values. I made a simple change to the code in SimObject.cpp:

bool SimObject::registerObject()
{
 AssertFatal( !mFlags.test( Added ), "reigsterObject - Object already registered!");
 mFlags.clear(Deleted | Removed);

  if(smForceId)
 {
  setId(smForcedId);
  smForceId = false;
 }

  if( !mId )
 {
  // New --------
  //Get a free ID
  int newId = Sim::gNextObjectId;
  for (newId; Sim::gIdDictionary->find(newId) != NULL; newId++);
  mId = newId;
  // ------------

  //mId = Sim::gNextObjectId++; // Old code
  dSprintf( mIdString, sizeof( mIdString ), "%u", mId );
 }

...

I ran this fine even after adding and removing 22 million objects using Demolishun's code. My ID remains consistent every time I start the mission (at 3919). However, I'm a simple-minded fool and haven't the slightest concept of the horrendous demonic forces this code could inevitably create. I imagine there might still be an issue with ghost IDs or something similar.

The value as it stands is still very high, but, and maybe I'm being overly OCD about it; the idea that there IS a limit and that every thing you do brings you closer to it really irks me. Every sound played or projectile created also add an ID that can't be reused. There must a good reason it's handled this way instead of my method above.
#7
04/23/2013 (1:38 pm)
@demolishun right! My bad was thinking that the amount was halfed but brainfuck made me half the exponent instead. Will correct it
#8
04/23/2013 (5:40 pm)
Okay, so this has been running since my last post. So for about 7 hours it is just now getting to 1 billion SimObjects created and destroyed. So I am a long ways away from the 2 possibly 4 billion needed to see a rollover/crash/etc.

So I guess I could let it run, or find a better way to test this...
#9
04/23/2013 (7:01 pm)
So rewrite your save/load system to save the type and attributes of your objects without the SimID, then create new ones on load. Load times will not be increased - the objects have to be created anyway.
#10
04/23/2013 (7:40 pm)
Everything is limited by the amount of ran and HDD space you have anyway so why worry about object ID's?

Is there a finite amount of energy in the universe or is someone adding more ram?
#11
04/23/2013 (8:01 pm)
I would be concerned for a dedicated server with persistent data. Not sure how long it would take to get to a huge ID value, but it could cause a need for a game restart. So I do see value in seeing if it does crash or cause issues once it loops.
#12
04/23/2013 (8:20 pm)
@Richard Ranft Nah, my save system never relied on IDs it's not an issue here, it simply led to me discovering this. I'm just half simply concerned about whether this could be a problem and half wondering why IDs aren't simply recycled to begin with. I definitely have a lot more to learn about Torque so I'm just trying to understand why things work the way they do.

@Demolishun That idea occurred to me as well, not relevant to my project but it did make me wonder.
#13
04/23/2013 (8:29 pm)
Quote:I definitely have a lot more to learn about Torque so I'm just trying to understand why things work the way they do.
I second this remark!
#14
04/23/2013 (8:43 pm)
Here is the answer:
Started up in 1.95 seconds...
2146584764
2146684764
2146784764
2146884764
2146984764
2147084764
2147184764
2147284764
2147384764
<input> (0): Unable to find object: '-2147483648' attempting to call function 'delete'
<input> (0): Unable to find object: '-2147483647' attempting to call function 'delete'
<input> (0): Unable to find object: '-2147483646' attempting to call function 'delete'
// this repeats ad inifinitum

To see this result faster I preset the dynamic value range like this:
// this line 299 in SimManager.cpp
gNextObjectId = DynamicObjectIdFirst + (2147483648 - 1000000);

So, that means scripting will fail when it does rollover at the 2^31 mark. I am sure if everything were treated properly as U32s it would just start overwriting object IDs at the 2^32 mark. Basically all hell breaks loose either way.
#15
04/23/2013 (9:44 pm)
Well, using my code from above I had a long check running which spawned in well over 2147483648 objects which I deleted immediately afterwards. The game then loaded, I entered my level and saved and loaded around 40 times. My player ID was still 3919 and I never encountered any issues.

So, why not use this method? I really don't know specifics behind how the system works, as I've said. From what I've gathered so far I haven't seen any drawbacks. I'll try looking into this further later.
#16
04/23/2013 (10:13 pm)
Well, if you're going to recycle IDs you might look into clearing associated entries from the SimDictionary -- recycle IDs and names....
#17
04/23/2013 (11:09 pm)
@Chad,
Sorry man, I did not mean to indicate that your code would not fix the problem. I was just finding out if there was a problem to begin with. I suspected there was after seeing your code changes, but I like to "see it happen". So yes I think your method is a good one and finding any issues associated with that change would go a long way to making it robust.

@Richard,
So is there a lot of latent data in there, or does it get updated when a new SimObject is created? Basically does it use the ID to index into the dictionary?
#18
04/24/2013 (3:32 am)
Chad: performance, I guess. Though I think usability is at least as important.

Here's a compromise: increment gNextObjectId as usual, but also keep a vector of 'hole' IDs. When an object is deleted, it adds its id to the list of 'holes'. When an object is created, it first tries to grab one of these 'holes'. If there aren't any (for example, at engine init) it takes gNextObjectId. There's a slight memory penalty, and occasional vector resizes, but you're looking at a nearly constant-time routine to get an ID for a new object.
#19
04/24/2013 (4:17 am)
@Demolishun,

Sorry wasn't thinking, I just quoted Lucas for ease on the int/uint size.
#20
04/24/2013 (5:01 am)
@Richard I think names are already cleared in unregisterObject() if I'm not mistaken. I'll look through the code later today and try to understand it better.

@Demolishun Understood, I had a check running before you posted your results I just wanted to see if mine would act the same as yours.

@Daniel That could be a good idea as well. Performance-wise I really didn't notice any issues, but, my testing level at the moment is quite slim.

It seems like a worthwhile effort to at least add a way to loop the ID count once it maxes out since it otherwise appears to be a sort of needless limit. Anyway, thanks a ton everyone. I appreciate all the input this topic got. Hopefully it helps others out as well.

Also, if performance did become a factor maybe allocating all unregistered objects into a list upon map ending or game reloading would be better.
Page «Previous 1 2