Radiant.call versus radiant.call_obj?

I see both these lines used often, but I’m not sure when one is more appropriate than the other. As I understand it, both are used to help JS communicate with LUA. Am I correct in thinking that ‘call’ is meant for client/server interactions, and ‘call_obj’ is a client only one?

My understanding is that ‘call_obj’ is like ‘call’ but is called “by” an object that you pass in. So you pass in a reference to a game object (like “game://object/1234” or something) to this function, along with the name of the function you want to call, and then it will call it with that object, versus just calling a function with the overall program. The code for these two functions can be found in “radiant.smod\js\radiant\object.js”.

3 Likes

Ahh what you say makes sense, although I don’t understand the implications of it! :smile: Thanks, if you wanna expand a bit more, thatd be great, but I will also look at the implementation you referenced, thanks :+1:

I may have been off with the “game://object/1234” thing, I’ve used that for traces before which I guess is a little different. But let’s look at two function calls in “stonehearth\ui\town\town.js” (disclaimer: I’m still looking at the code from two unstable versions ago, so line numbers might be different, because I can’t be bothered to delete my extracted version and re-extract the latest :stuck_out_tongue: ):

line 73:

radiant.call('stonehearth:get_town')

‘get_town’ is the name of a function in the ‘stonehearth’ namespace; we ask that this function be called and the result be returned. You could imagine a function in which an argument is also passed, say something like ‘get_player’ with a ‘player_id’ argument passed in. That would still be called with ‘radiant.call(…)’.

line 126:

radiant.call_obj('stonehearth.inventory', 'get_inventory_capacity_command')

‘get_inventory_capacity_command’ is the name of the function we want to call, but the function doesn’t exist in a global sense, it needs to be called specifically by the ‘stonehearth.inventory’ object. So it’s essentially calling ‘stonehearth.inventory.get_inventory_capacity_command()’. But because ‘stonehearth.inventory’ is an instantiated object and not just a namespace, it needs to be passed in separately so the program can parse it correctly.

A few lines down (line 134 for me) you can see a similar call but with an added argument that’s being passed to that function as the third parameter in the ‘call_obj’ function call.

Anyway, that’s my understanding, but I’m still pretty new to this and don’t have any background in web development languages.

1 Like

I would like to object the phrasing a bit. You’re not calling something “by” an object, you’re calling something on an object. It’s a method invocation.

radiant.call_obj('stonehearth.inventory', 'get_inventory_capacity_command') is basically stonehearth.inventory:get_inventory_capacity_command() in lua (is the same as stonehearth.inventory.get_inventory_capacity_command(stonehearth.inventory)). stonehearth.inventory is a service (the inventory service) of the stonehearth mod, registered on the server side by SH itself. If I had to wage a guess, you could access at least mods and their direct fields that way, but it could probably work for all global variables.

radiant.call is able to call pre-defined functions in the manifest (the functions part of it) on either server or client side (originally very popular for commands) and is the usual, generic go-to way to communicate with the lua side from JS (and, to some extent I suppose, from the client to the server. Not sure if vice-versa is a good idea anymore).

radiant.call_obj is able to call it on some object (object_commands) and is seemingly server-only, but able to directly invoke methods without needing a specialised function method.

There’s advantages and disadvantages to each of them:

  • If you’re doing a quick query, or a simple command, and you already have a service/controller in place that also happens to have just that method already in use somewhere else (on the lua side), call_obj can simplify things a lot.
  • If you’re trying to call something on any lua object in general, radiant.call_obj can be useful because it avoids writing boilerplate code for the callback. That only works if you have the reference of course - if you need to find the object somewhere, it might be quicker/easier to write a normal radiant.call callback instead.
  • If you need more advanced promise resolution (e.g. your action could take some time before you can return a result, or you need to be able to fail in a specific way, or maybe report progress), then a callback function with radiant.call (which might just be a wrapper) would be the way to go. Examples would be the whole selector business, which need to prepare some bits in lua, then wait for the GUI to do the selection, then do some more lua, and then return with success/failure (I think, it’s been a while).
  • If you need to call something on the client, then it’s (seemingly?) always radiant.call

When in doubt, use radiant.call and write a callback method. You can’t really go wrong, and in the worst case, you’ll just write additional code.

5 Likes

Awesome! Thank you!