Sign in to follow this  
Ezbez

Unity Question regarding indexes to entities and scripts

Recommended Posts

From this thread.
Quote:
Original post by ApochPiQ
Quote:
Original post by Nitage In fact, I find reusing Ids a bit nasty - what happens if (say in an rts) a unit diedhalf an hour ago, but a script kept around a reference to it? Do you want to be able to tell the script that the unit in question no longer exists? Or would you prefer to hand it a reference to a totally different unit?
If this scenario ever occurs, you have serious design issues anyways, and likely some major bugs lurking under the surface. When the unit dies and becomes non-existent, every reference to it should be released. Your systems should be built in a way that makes it trivial to track all known references to a given resource or entity; as a logical consequence, it should be trivial to remove those references if an entity stops existing. If this is not a very simple process, chances are the design has some major weaknesses - most likely excessive coupling, probably some temporal coupling, and certainly a lot of unwritten and unverifiable assumptions.
This scares me because it's basically saying "Your program is going to have bugs, Ezbez!" I have a system similar to what was discussed in the linked thread. I have integer IDs for everything, and I create a new one by adding one to the last one that was made. No duplicates, no worries, eh? But now ApochPIQ tells me that it's fundamentally wrong and the very fabric of game-time is going to collapse on me one of these days because of it. Can anyone help me with this? I want a nice system, but I'm not sure how I can improve upon my current system. I guess some more details about my current system might be useful. I internally store Entities and expose them via EntityHandles to scripts. The EntityHandles don't actually ever give out an Entity, they wrap all function calls to the Entity between another layer. This layer checks that the Entity is still valid, if not, it does nothing and returns some generic nothingness to do no damage. Scripts only ever touch EntityHandles, and can store them. EntityHandles internally store indexes to the Entities.

Share this post


Link to post
Share on other sites
When your entity dies, all references in the scripts should die too, so they should never have to manage a NULL handle. Else, you scripts might for example, leak memory quite badly (for example, accessing the entity one hour after its deletion. That's not really a good idea).

It is not recommended to silently discard NULL handle. At the very least, assert. It's like a memory violation, like accessing a dangling pointer. The exception is that you can obviously carry on the execution, during the development time. But in final builds, these should be ironed out.

If you are not confident with re-using Ids, that's fine (as long as you use a fast lookup / hash table), but consider accessing NULL handles to be a bad thing at least.

Share this post


Link to post
Share on other sites
I use references to pass around.

Since the code requires either serialized references or local objects, I use a single reference that stores the serialized id and smart pointer.

Then I overload the -> and * operators to make handling transparent.

Something like this:

template < class T >
class ObjectRef
{
public:
ObjectRef( ObjectPtr ptr )
: m_ptr(ptr)
, m_guid(ptr->guid())
{}

ObjectRef( ObjectGUID guid )
: m_ptr(NULL)
, m_guid(guid)
{}

T operator ->() {
{
if (!resolve() ) throw ...
return m_ptr;
}
private:
bool resolve()
{
if ( m_ptr.is_null() ) {
// do lookup to obtain instance
if ( ... not found ... )
return false;
else
m_ptr = ....
}
return true;
}

ObjectGUID m_guid;
ObjectPtr m_ptr;
}




The scripts are passed the ObjectRefs.


void invoke_action( EntityRef &ref )
{
... script( ref )
}




Here, I don't fuss much if object gets "destroyed" while script is holding a reference to it. Smart pointers make sure the object is still around, it's just disconnected from the event system.

And since all scriptable actions can only hold references for duration of function call, this overlap is minimal.

This isn't optimal, and I use it in networked game, so my requirements might be somewhat different, but they do the task.

When an object is destroyed, it's simply removed from global directory. Smart pointers take care of the rest.

In addition, it allows me to defer resolution of serialized references until they are needed - some might never need to be resolved.

Share this post


Link to post
Share on other sites
This reminds me of a minor bug in Warcraft 2. Summoned skeletons have a timed lifespan, after which they automatically die. A player can load a skeleton onto a transport ship and then wait for it to die. The slot on the transport will then appear empty. The next unit created will appear inside of the transport instead of where it was supposed to. Even units that shouldn't be allowed on the transport, like flying units, other ships, enemy units, and buildings. The bug wasn't that serious because summoned skeletons were fairly worthless and have a long lifespan, so it didn't happen in real games.

Just an example that shows this sort of bug has actually occured in commercial games.

Share this post


Link to post
Share on other sites
But how can I fix it? I'd like to be able to keep references in scripts for longer than the duration of one script. And I'm not sure how I'm supposed to go about handling the removal of all references. I could do that, but I'm not sure how that will work for scripts. For example, if Entity A gets a reference to B, then B dies. What should A do if it's handle to B disappears? Suddenly it'll be accessing a non-existant variable - the very thing I was trying to avoid when I created EntityHandles.

Edit: Though I don't really see how it takes care of the problem at hand, I really must say that I like your system Antheus. It seems like just the thing I was looking for to avoid having to do a lookup in an std::map every single function call.

Share this post


Link to post
Share on other sites
Essentially you have a requirement, which is to ensure that your references stay safe to use. Either that can be by magically removing all references to something unsafe, or it can be by making references to dead things just as safe as references to living things. The first way requires that each entity knows who refers to it (eg. observer pattern, smart pointers), but gives you the benefit of knowing that you never have null references.

Either way requires that you have a system in place for handling what happens to a script with a null reference. If your language uses exceptions, defining a standard exception for this purpose makes sense. If not, you have various choices - the 'generic nothingness' of the original post is one option, though perhaps not the easiest to debug when scripts misbehave.

In other words, I think ApochPiQ is perhaps overstating the problems. It's safe to keep dangling references if your references are safe to use, and if you don't recycle ids. If either of those are false, you need to get rid of references as soon as they become invalid. That's all.

Share this post


Link to post
Share on other sites
Okay, neither of those are false for me, so I'll just keep it how it is right now, but I'll throw an exception if it no longer exists and is accessed.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Announcements

  • Forum Statistics

    • Total Topics
      628320
    • Total Posts
      2982057
  • Similar Content

    • By PING YI LIN
      Hi,
      I am an indie game developer from Taiwan.
      This is my game” Wo Yao Da”, which is on sale on Steam now.
      Wo Yao Da video
      Wo Yao Da is a third-person ARPG game, in which the player plays as a tribe warrior and a mysterious weirdo, adventuring in the world of gremlins.

      The tribe warrior is good at using knife, spear, bow and arquebus, and his prototype is the warriors from the Gaoshan Tribe (high mountain tribe) in Taiwan in the early 19th century.

      While the prototype of the mysterious weirdo is the founder of a “special” and new religion. He created a series of “Buddha dance.”
      STAR WARS 莊圓大師
      再掉槍啊
      【莊圓大師 : 對十方世界的復仇】1080p高畫質正式中文預告片,全球搶先上映!(HD)
      He does behave rather differently and in the game, the player attack just like whatever he does in real life, such as rolling on the ground over and over and over… oh yes, that Buddha Dance too, which is something you don’t want to miss.
      I did refer to objects in history for the costumes and buildings, but the story plot is a work of fiction. Please take it lightly and have fun.

      The gremlins in this game looks like this:

      Thank you.
      Steam Page: Wo Yao Da 我要大
    • By Hilster
      Hello 2D Artists,
      I've started making a 2D Puzzle Adventure game for mobile and I'm looking for someone who would want in on creating assets for the game. The core of the programming is pretty much complete, you can walk within the grid laid out and push boxes, when there is an object on top of a pressure pad it will activate the linked objects or if there is one object with multiple linked pressure pads it requires you to activate all points for the object to become active. 

      The level iteration for the game is quick and simple, a Photoshop file that is made of individual pixels that represents objects is put into the game and it creates the level out of those pixels with the assigned objects.
      The objects that need sprites created so far is the character, box, pressure pad, door, trap door, the walls, the stairs and the tiled background.
      I intend to add more objects so the amount I'd like to add will be extended.
      My motivations for posting here is to have something that looks nice to be able to display on my portfolio, so if you're looking for a working game that you can place your art into and improve the look of your portfolio then we're in business.
      Please reply with a few past examples of your art below and I'll be in touch!
    • By thefollower
      Hi
      I have set up my TcpClient to connect to my server and that works fine. But i am a bit confused how i read messages from the network stream with it continuously running via async, without ever closing the connection ?
      My TcpClient Manager class has:
       
      public async Task<bool> Connect(string address, int port) { try { await _tcpClient.ConnectAsync(address, port); IsConnected = true; return true; } catch(Exception e) { Debug.Log(e); return false; } } public async Task<int> Read(byte[] readBuffer) { if (!IsConnected) return -1; using (var networkStream = _tcpClient.GetStream()) { try { var bytesRead = await networkStream.ReadAsync(readBuffer, 0, readBuffer.Length); return bytesRead; } catch (Exception e) { Debug.Log(e); IsConnected = false; return -1; } } }  
      So i thought to just run a co-routine and call Read constantly to get the most recent message, but that doesn't make much sense to me since a co-routine would be blocked with the await. How is this actually done? The MS Docs don't have very good Async examples with the TcpClient class so i don't know fully get how to keep calling Read correctly.
    • By NUITGaming
      Landscaping back ground maid in Unreal 4.18
  • Popular Now