Fri Nov 10, 2017 5:59 am
Welcome, Bdav! Sorry I missed you yesterday. Glad to see you here - and I hope we see more of you in the future.
Welcome! Glad to see an old lurker make their first post :3
I just asked Josh your question. Here's his response:
Actually Josh wrote:Naturally I will document how to do it -- making LT moddable has been a huge time & engineering cost, there is no way that I'm going to make it 'technically' but not 'practically' moddable...I respect my own time more than that xD
Trivially, it seems like any script that remains active for the duration of the game session should have at least one call to `sleep` in its loop. It appears that Lua allows for higher-order functions, so perhaps a modder could write a script for what happens in one iteration of their loop, and they pass it to a function called something like `LTLoop` which takes their function, and any arguments that their function needs, as arguments?Flatfingers wrote: ↑Fri Nov 10, 2017 12:46 pmAnd now there's the new LT scripting language, which again expects programmers to alter the natural structure of their code so that sleep(x) statements can be inserted in efficient places. This presumes that the people who want to mod LT with scripts will know how/where/when/why to inject a sleep(x) call.
None of this is intended in a critical tone. It would not be wise for me to criticize any technical solution Josh produces. If the best route to LT scripting that is powerful, performant, and relatively simple to support is to have scripters figure out where in their code they need to temporarily yield control back to the CPU, then that's just how it is.
I guess I'm wondering: would it be a good idea, if People Who Are Not Josh will be expected to shoulder that responsibility, to help them out by describing the rules for knowing where to put sleep(x) calls?
Code: Select all
def mod_loop_logic(*args): # loop statements go here def mod_setup_logic(*args): # this is only executed once to set up the mod # ... # elsewhere, LTLoop is defined as something more or less like this: def LTLoop(func, *args_for_func): dt = LTSleep() # I'm going to assume we have some wrapper for `sleep` here that uses a sensible waiting interval and isn't very greedy while dt: func(*args_for_func) # unpack the varargs dt = LTSleep() # ... # then the actual mod script could be something like def mod_execute(foo, bar, baz. quux): mod_setup_logic(foo, bar) LTLoop(mod_loop_logic, baz, quux) return
Code: Select all
def mod_execute(foo, bar, baz, quux): mod_setup_logic(foo, bar) dt = sleep(0) while dt: mod_loop_logic(baz, quux) dt = sleep(0)
I guess it means that there won't be so many coroutines. Or that he already has a great solution, and it will come in a future log (one can hope!). Thanks for asking himLindseyReid wrote:Josh says the short answer to your technical question is "no, it's not a problem". But I bothered him in the middle of coding to bring the question to his attention, LOL, so he may give a longer answer later :V
Happy to have you back Flat, but equally happy to know you do get away for breaks
bdav wrote: ↑Sat Nov 11, 2017 5:09 amFlatfingers, it's true that this cooperative scheduling adds some constraints on the modders. But I still thinks it is done the right way for two reasons:
- These are not programs, but scripts in a game engine. They are usually either event-driven or at fixed frequency, and in both cases they will naturally yield. As Josh said, there is a lot of sparsity in the execution. There may be some difficulties with scripts that need very long computations though.
- All the coroutines are in the same process, sharing the same data. The cooperative threading acts like a synchronisation mechanism, but if you remove it (for instance by pre-empting), you need to add some other kind of synchronisation. I believe it would be more painful (and a waste of CPU) to have mutexes rather than yields. My point is that, in the cases that are difficult, the alternatives that I know of seem even worse.
Users browsing this forum: Majestic-12 [Bot] and 1 guest