Persistent objects
#1
If I were to ask, "what is the single most unintuitive thing in MCS plugin development", I'm pretty sure most of the answers would be "DoWithXYZ callbacks". The dreaded Lua object lifetime problem, when the Lua object is valid, but the underlying C++ object may have gone missing already.

Now what if I told you it doesn't have to be this way. Have a look at the cNetwork API - it doesn't suffer this issue, although the conditions are the same - the connection may go away at any point, the remote peer can disconnect at any time, yet it's perfectly valid to keep the cTCPLink objects in Lua and call operations on them long after that. Have you even noticed this little "revolution"? Smile

The way to do this is a bit of black magic - all such objects need to be represented as SharedPtrs and they need to take and release ownership of themselves at certain times. But it can be done.
One problem though - it means writing an awful lot of glue code. ToLua cannot generate bindings for these, it all needs to be hand-written. And it would need rewriting almost everything in the server, instead of passing raw pointers around to passing SharedPtrs around. But it can be done.

The question now is: how much determined are we to make a change? Are we? Or is the status quo good enough so that we needn't bother?
Reply
Thanks given by: sphinxc0re
#2
Though it would be nice to have since some people are sometimes asking for it, is it worth it to go through the trouble?

On the other hand, if we want to do it later we'd probably have to rewrite even more code.
Reply
Thanks given by: sphinxc0re
#3
1. Create Bindings.cpp
2. Replace all "cPlayer" -> "SharedPtr<cPlayer>"
3. ???
4. Profit

?Tongue
Reply
Thanks given by:
#4
@FakeTruth: Nope. The Lua bindings still get the raw pointer, but everywhere else the pointer should be replaced by SharedPtrs.
Reply
Thanks given by:
#5
I suspect that tolua can be patched to generate the bindings automatically, if we wrote the appropriate support code. What the code you've written does in each case is hide the pointer to pointer. With a template we can generate the wrapper classes automatically.

However we need to be careful with the DoWithXYZ objects as a lot of them are about locks, a concept which lua does not express well.
Reply
Thanks given by:
#6
I don't think this is safe for most of the API. The difference between most of the DoWithXYZ vs the networking code is observability. Nothing other than plugin and plugin support code is interacting with a cTCPLink. So a plugin can mutate the Link any time it likes. WIth an entity retrived from DoWithEntityByID there is nothing that you can safely do outside the callback. Yes we could slightly simpilify the code with a handle object to hide the fact that you have to store the ID and not the pointer, but anything else would have severe multithreading issues. You still need the callback.
Reply
Thanks given by:
#7
I think it is worth noting that rust is currently developing a similar API pattern (https://github.com/aturon/rfcs/blob/scop...-take-2.md ) to deal with the fact that destructor's are not guaranteed to be called. In a language where you do not have the guarantees of destructors being called, callbacks are the only way to guarantee correctness of locked objects.
Reply
Thanks given by:




Users browsing this thread: 2 Guest(s)