[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: dynamically loading/unloading plugins (was: Re: Scripting)



Gregor Mueckl wrote:

> >>>So, you can actually edit and recompile parts of your program WHILE
> >>>IT'S STILL RUNNING!!
> >>>
> >
> >
> >>This works only if you have C-ish interface between the module and the
> >>core engine.
> >>
> >
> > That's not *entirely* true - but I don't think the interface between
> > the core engine and a script interpreter would be likely to be any
> > better.
> >
> 
> Sorry. I don't understand this sentence. Could you please paraphrase it?

It's not entirely true that re-linking on the fly only works if you have
a C-ish interface between the module and the core engine.  There are ways
to avoid that - although I agree that it's not exactly easy.

But I don't think the restrictions imposed by choosing a 'C-ish interface'
are anywhere near as bad as the restrictions imposed by the alternative
strategy of using an interpreter to run your scripts.  Invariably, the
bridge between your core engine and the scripts is REALLY ugly because
the class structures of a C++ language never map really well onto the
scripting language's class system.

So, I don't think the supposed restriction of having to use a 'C-ish'
interface to a ".so" library are a worthy reason not to go that way.

> > But none the less, what I said is true - you can edit and recompile
> > "scripts" written in C or C++ without restarting the game - you may
> > have to be kinda selective about how you call it - but that's a small
> > price to pay if your only alternative is to resort to a really slow
> > interpreter.
> >
> 
> Whether the price is small depends on one's point of view. My point was
> that you didn't explicitely restrict your statement in scope. You said
> "it works". I took it for "it works in all cases", which is a wrong
> thing to say. And I wanted to point that out.

"My Car works" doesn't mean "My Car works in all cases" (eg at the bottom
of the ocean).
 
> > As I have already said, there are several other reasons to prefer
> > an interpreted script - but hot-swappability isn't one of them.
> >
> >
> >>But what if you pass on an instance of a class that's
> >>implemented in the module on to the engine and loose track of it (you
> >>would have to replace it, anyway)?
> >>
> >
> > Well, you could work around this if you wanted too.
> >
> 
> How?

Resource managers - you basically don't lose track of things you give
to a script.  Use reference counting and such like to ensure that any
resources the script consumed are free'd up when it's booted out of memory -
unless they are in use elsewhere.

Actually, I wouldn't bother with that too much - I can stand a little memory
leakage during testing and script debugging.

> I'll give you an example of a situation that (a) probably won't work and
> (b) is hard to avoid (IMHO):
> 
> The main engine defines some interface class (say, for an in-game-object):
> 
> class A {
>    public:
>      virtual void foo() = 0;
> };
> 
> The plugin provides a derived class and a suitable create() function for
> such an object:
> 
> class B : public class A {
>    public:
>      virtual void foo()
>      {
>        // some code here
>      }
> }
> 
> B* create()
> {
>    return new B;
> }
> 
> On calling create() the engine gets a poiner to this object, which it
> most likely merges somewhere into the scene graph and maybe into some
> other places as well, but by doing so it must loose the exact type
> information of this object as the exact type is only known by the
> plugin, along with the code for the function B::foo(), which is called
> by an indirect reference in the vtable of class B, that also resides
> within the plugin (and not within the object). So the situation is that
> (a) you can't reliably find the object and replace it and (b) would
> crash the engine after you reloaded the plugin while such an object is
> present because the pointer to the vtable the engine's instance of B
> carries becomes invalid and the next call to B::foo() will go into nowhere.

Since A is a part of the core engine (if I understand your example correctly)
then it can arrange to identify itself as something created inside a particular
script (eg set a global "inside_script" to the scripts identifier before you
call the script) so that A's constructor function can add itself to a list
of "resources_owned_by_script".

Since B is derived from A, it'll be well-behaved in that regard - and so long
as it has a virtual destructor function, the core engine will be able to
cleanly remove it along with any other resources owned by that script.

> Even if you solve the first problem, you will still have to find all
> pointers to this object everywhere in your engine and you will have to
> replace them with pointers to an instance of the updated class, which
> preferably gets a state on its creation that is in sync with the rest of
> the game world.
> 
> I don't know how you can solve all this. If it can be done at all (which
> I doubt), it can't be done without a ton of code and performance losses
> due to management overhead (both of which hamper the game engine).

Well, you may be right - but that doesn't make it impossible - only undesirable.

Since I don't find the use of C/C++ for scripting desirable for *other* reasons,
I don't think this is an especially important argument.

----------------------------- Steve Baker -------------------------------
Mail : <sjbaker1@airmail.net>   WorkMail: <sjbaker@link.com>
URLs : http://www.sjbaker.org
       http://plib.sf.net http://tuxaqfh.sf.net http://tuxkart.sf.net
       http://prettypoly.sf.net http://freeglut.sf.net
       http://toobular.sf.net   http://lodestone.sf.net