Page 1 of 1

Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Mon Feb 19, 2024 3:21 am
by BurninSun
Currently, if I want to call a remote interface, I have to do something similar to

Code: Select all

if remote.interfaces["iface"] and remote.interfaces["iface"]["ifunc"] then
	local ret = remote.call("iface", "ifunc", myargs)
	dostuff(ret)
end
Every call to `remote.interfaces` requires the engine to create a dictionary of dictionaries for all interface names and all function names which we only use to check an interfaces existence then throw away.

(Alternatively, that code can be rewritten so that `remote.interfaces` is only called once, but still, my point remains)

The problem: This is a relatively slow process to create this dictionary of dictionaries into Lua.

These values cannot be cached as remote interfaces can be added and removed at any time. (Alternatively we can use `xpcall` on `remote.call` without checking a functions existence, but that becomes a huge pain to handle for something that should be simple.)

It seems it would be simple for the engine to trigger events `on_remote_interface_added` and `on_remote_interface_removed` as appropriate. Included in the `event` data would be the name of the interface added or removed. The actual function names included in the interface can then be retrieved with `remote.interfaces[event.interface]` and kept in a cache. Then when I need to do a remote.call I simply check my cache for the functions existence and call it.

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Mon Feb 19, 2024 5:34 am
by FuryoftheStars
Can you give a usage example on this? IE, in what situation is this useful? My understanding on remote interfaces has been such that these aren't things that are (or should be) dynamically added or removed during runtime. As such, it's either there because the mod that makes it is there, or it isn't because the mod isn't, and so you either require the mod for your mod, or you check for that mod's existence before running your call. I feel like a mod dynamically adding or removing interfaces defeats the point of the interfaces and is just asking for trouble.

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Mon Feb 19, 2024 10:22 am
by BurninSun
While I agree with your sentiment, the fact is that interfaces can be added and removed on the fly. So do we just call it and hope another mod hasn't removed their interface then take the bug reports if it has?

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Mon Feb 19, 2024 1:49 pm
by FuryoftheStars
Honestly? As a mod author attempting to make a mod to go along with another and use their remote interfaces, I'd file a bug report to their mod and explain why that's an issue doing that.

I suppose if someone could come up with a great example where calling these functions dynamically would be beneficial, I could see this, otherwise I'd rather propose to the devs to restrict the usage (if it's possible) of these functions to being able to run only in the root, on_init, and/or on_configuration_changed code spaces (and any other "executes once" code space that I'm forgetting and makes sense). Or, I just wouldn't sweat it until I ran across someone that was doing this and either refused to (or couldn't because they were gone) change it, then I'd find a work around if possible (maybe even release an alternate version of the mod if they were indeed gone).

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Mon Feb 19, 2024 2:46 pm
by curiosity
Why is this better than adding a function like this?

Code: Select all

LuaRemote::try_call(interface, function, ...)  → boolean, Any?
Assuming call errors when given a nonexistent interface/function name instead of doing something similar already.

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Mon Feb 19, 2024 10:54 pm
by BurninSun
Restricting usage during on_init and similar would also work, but that is not a system that the engine currently does. Creating that system and explaining it to the modders would be a big undertaking for such a rarely used feature.

LuaRemote::try_call would work similar to pcall(remote.call, "iface", "func", ...) though pcall has the issue of catching any errors in the remotely called function. Otherwise, that could work as well.

With events as proposed, I'd imagine it would be simple to implement and go along nicely with the other similar features in the engine.

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Wed Feb 21, 2024 5:32 pm
by curiosity
BurninSun wrote:
Mon Feb 19, 2024 10:54 pm
With events as proposed, I'd imagine it would be simple to implement and go along nicely with the other similar features in the engine.
In the context of the problem you are trying to solve, it's a suboptimal solution. You have to set up caches that you need to keep updated, handle events and so on. As opposed to simply having the game do what it already has to do to call the function in the first place.

Re: Add events for `remote.add_interface` and `remote.remove_interface`

Posted: Thu Feb 22, 2024 2:36 am
by BurninSun
curiosity wrote:
Wed Feb 21, 2024 5:32 pm
In the context of the problem you are trying to solve, it's a suboptimal solution. You have to set up caches that you need to keep updated, handle events and so on. As opposed to simply having the game do what it already has to do to call the function in the first place.
Some remote calls are generic and the interface is unknown. For example, space exploration beacon overload has the following when an entity is reactivated due to beacon overload being disabled.

Code: Select all

for interface, functions in pairs(remote.interfaces) do -- allow other mods to deactivate after
  if interface ~= "space-exploration" and functions["on_entity_activated"] then
    remote.call(interface, "on_entity_activated", {entity=entity, mod="space-exploration"})
  end
end
In this case, `try_call` would not work as the interfaces would not be known. Caching the interfaces from `remote.interfaces` also would not work as the callee might only enable that interface after a specific event (eg. an entity needing to receive this callback being built).

There is another similar "unknown interface" callback when space explorations deletes a surface. Informatron also uses this construction.

Having interface events would allow modders to either use the existing `remote.interfaces` for simplicity of coding or use the events to track available interfaces for performance.