[NLua] How to provide the lua state with a dynamically accessible class
I have a
Service
class that contains different services that relate to the game, like Player, WorldState, etc. I want to provide access this class to the lua state in a way where it is newly accessed each time it's called. So not just doing
because that will lead to the values being cached on load, and not accessed whenever they're called in a lua script. The goal is to ultimately be able to just call Service.Player.Position
or Service.WorldState:GetMapName()
(or formatted reasonably similarly) and fetch the value on call.
There are hundreds of functions and properties within the service class so I'm not interested in making wrappers for all of them either and registering them individually. This seems very straightforward to accomplish and that I'm missing someting obvious, but the lack of nlua documentation is getting to me.16 Replies
so your goal is to achieve something akin to lazy property access? so instead of assigning
foo
at the moment of intialization, you want to defer fetching that value until the lua code tries to access foo
?Yes, per-access too to be clear
i'm obviously making a lot of assumptions here based on the fact that this is (I assume) for lua scripting in a game/engine, so feel free to correct me:
assuming, like many games do, your lua code is executed once per frame/event/etc, is there a particular usecase for you wanting or expecting these properties to return different values each time they are accessed? in the few games I've written lua scripts for generally your events or callbacks are a "snapshot" of the game state at that particular moment so expecting multiple different return values for a property just doesn't make sense to me?
technically speaking you could defer this by using
Func<T>
instead of T
directly. Not sure how that would work within NLua...I use Laylua for my Lua scripting needs (looks very similar to your example) but I've never used it in a game 😅for lua scripting in a game/engineThat would be correct.
is there a particular usecase for you wanting or expecting these properties to return different values each time they are accessedwell yeah, the game is changing every frame after all. Like if you have a lua script where you want to execute something when
Servce.Player.ZoneId == 1
you'd just loop checking the value. It wouldn't be helpful if the value is cached on script start or on first access.
I do have it setup to be able to trigger scripts on conditions, where you'd really only care about a "snapshot" of the game as you said but it also has the ability to just run scripts alongside the game for an indefinite period of timethen yeah, I would register it as a function than a value. I'm not sure how it works in NLua, but...if these are auto-properties I think you can even use the GetMethod directly...
I've never used property GetMethods before but I know of their existence. Feel free to mess around with it. if you absolutely insist on making it a property instead of a function in lua there might still be a way to get a new value each time via Func<T>.
Yeah that's something I've tried before, but it really just ended up with null values, probably because I'm not fantastic with reflection. This was one iteration for reference
I think NLua lets you effectively inject C# objects into your code already...it feels like you might be re-inventing the wheel already. Are they copied by value and don't change every frame, so that's why you're trying to do it via reflection? Laylua has what it calls Value Marshalling which lets you do just that. I asked the dev if it's copied by value or if it's actually pointing directly to the reference (i.e. volatile/can change on access like you want)...haven't heard back yet
I think NLua lets you effectively inject C# objects into your code already...it feels like you might be re-inventing the wheel already.this very well might be the case and I've wasted hours on this but finding out info about nlua is like pulling teeth
Are they copied by value and don't change every frame, so that's why you're trying to do it via reflection?as in they're all structs or primitives? Yeah mostly. There are quite a few pointers but I'm mostly not worried about those
What I guess I meant was: if you can figure out how to access c# types from within nlua, see if changing the value on the outside changes the value on the inside. I have a feeling it won't, but it doesn't hurt to try
Sorry for the botched screen shot, but this is on NLua's readme.md

cannot for the life of me figure out doing it like that import statement. I can however do
Can't test if it actually accesses it on call though since it seems to crash when called in a loop... Works as a one liner at least
if you can find a way to have a safe accessible class that wraps whatever your service is I don't see why you wouldn't be able to just do...
or
well really not sure how the current service class is unsafe. If I do a simple
It results in the same as the last message where it can be accessed once, but multiple lines (like in a loop), it causes a crash. I was thinking maybe it's a speed limitation of the CLR access in nlua but it doesn't matter how fast or slow I access it a second time
yeah I'm not sure why accessing the property throws a second time. NLua docs are sparse as you mentioned...I saw they have a wiki but the TOC is like...to articles that are imaginary lol. If you are not super tightly coupled to NLua already, give Laylua a try. it's certainly much newer and more experimental than the other "big" C#/Lua interop libraries, but I've been using it for my Discord bot for custom commands for almost a year and it's been working great. The dev has been very helpful at answering questions directly in the help server. And it is generally "crash" proof as the sandbox is designed to not crash the entire app if something happens in Lua, which I believe is a notable difference from some other libs.
I've had a pretty simple experience interfacing with C# types in lua, though maybe my solution isn't applicable to every situation (or yours). I just added a little abstraction which my lua-facing types inherit from and then the class would be properly passed into the sandbox as userdata
I might give it a try. Not super tied to NLua specifically, it's just what my program used before this rewrite so I'm most familiar with it, though that's not saying much
Well seems like this may be a solvable problem. The crashing was apparently unrelated but it does throw an error.
I can access it multiple times, but only if there's no waiting in between, so e.g. on the same frame where it's not helpful to access it multiple times. If there's a wait, then the properties are all nulled, but only for the imported class. Regular functions work fine after a wait
i'm gonna guess that coroutines are incompatible with how NLua copies C# data into it
so it's likely that maybe it's somehow on another thread where those properties are no longer accessible
just a guess, though. see if you can find another way to "wait" instead of using
yield