What is setUserData and why do I need it?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Jugbot
Prole
Posts: 11
Joined: Mon Jun 24, 2019 9:54 pm

What is setUserData and why do I need it?

Post by Jugbot » Thu Jul 11, 2019 5:34 pm

The wiki wasn't very clear about this and as far as I've seen it looks like a way to tag love objects with simple types.

Am I right in that you cannot add properties directly to a love object (such as Joint.myval = "hi")?

And as an extension to this question, what would I do if I want to modify data through setUserData? Would I have to get-modify-set every time?

User avatar
raidho36
Party member
Posts: 1804
Joined: Mon Jun 17, 2013 12:00 pm

Re: What is setUserData and why do I need it?

Post by raidho36 » Thu Jul 11, 2019 6:52 pm

TL;DR: just ignore it.

This is physics-specific; yes you will have to get-set the data. This feature is generally pointless, considering that you can simply use a table lookup instead and it'll work faster on account of not having to do the C++ to Lua transition and back.

Code: Select all

userdata[physicsobject] = whatever
These non-native Lua objects are "userdata" (Lua terminology) and Lua cannot operate on them, only C++ code can; they can have metatables, so you could fill it up with C++ functions and use these types of objects the same way you use a table, except that you can't actually perform any operation on them from Lua side. This is why you can't write or read any properties from them, but you can execute "class" functions on them. With that in mind, the "set/getUserData" is a confusing name for this function, which basically just attaches Lua value as a payload to it on the C++ side, not actually does anything with userdata. And on top of that, it will actually crash your game if you attempt multithreaded use, because the Lua payload is only valid for whichever Lua thread created it.

Jugbot
Prole
Posts: 11
Joined: Mon Jun 24, 2019 9:54 pm

Re: What is setUserData and why do I need it?

Post by Jugbot » Thu Jul 11, 2019 7:22 pm

I'm glad I asked this question, a lot of this should be on the wiki >.>

TheHUG
Citizen
Posts: 51
Joined: Sun Apr 01, 2018 4:21 pm

Re: What is setUserData and why do I need it?

Post by TheHUG » Fri Jul 12, 2019 4:15 pm

When you have some collision callback that only sees two fixtures (to which last I checked you can't assign any attributes as they are not tables), you may want some way to reference the object they came from to e.g. change its health without requiring a global variable. The simplest way is to store a reference to their 'parent' object inside them. That's what I used get/setUserdata for anyway. It was pretty handy in that sense.

User avatar
ivan
Party member
Posts: 1454
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: What is setUserData and why do I need it?

Post by ivan » Sat Jul 13, 2019 3:32 am

Yes, setUserData is very useful when associating a body to a Lua object.
raidho36 wrote:
Thu Jul 11, 2019 6:52 pm
This feature is generally pointless, considering that you can simply use a table lookup instead
But then you have to modify the table every time a body is created or destroyed.

User avatar
4vZEROv
Prole
Posts: 36
Joined: Wed Jan 02, 2019 8:44 pm

Re: What is setUserData and why do I need it?

Post by 4vZEROv » Sat Jul 13, 2019 8:09 am

It's not useless a all ! You can't directly set values to a body or a fixture (fixture.x = "hello").
I use it in my physics library if you wan't a real usecase :

https://github.com/4v0v/physics

User avatar
pgimeno
Party member
Posts: 1690
Joined: Sun Oct 18, 2015 2:58 pm

Re: What is setUserData and why do I need it?

Post by pgimeno » Sat Jul 13, 2019 9:41 am

ivan wrote:
Sat Jul 13, 2019 3:32 am
But then you have to modify the table every time a body is created or destroyed.
As for creation, in the other method you have to setUserData anyway, so there's no significant advantage - both methods require an action at creation time. As for destruction, weak tables take care of that automatically. The only extra work is a one-time setup of the weak table.

So for example:

Code: Select all

local bodyData = setmetatable({}, {__mode = 'k'})

function createBody(x, y, extradata)
  local body = love.physics.newBody(world, x, y)
  bodyData[body] = extradata -- instead of body:setUserData(extradata)
  return body
end
As an extra bonus, bodyData is not accessible from other threads so you can't get crashes as you do with setUserData if used from another thread. It can also be hidden from user code, so it can be used in libraries transparently.

As another extra bonus, this method is usable with any object, not just physics objects.

User avatar
ivan
Party member
Posts: 1454
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: What is setUserData and why do I need it?

Post by ivan » Sat Jul 13, 2019 11:09 am

Looks much cleaner using setUserData and it doesn't require the "bodyData" global.

PS. Also, I tried the weak table technique and it didn't work as expected.
Weak keys are collected almost right away regardless of whether the bodies are destroyed or not.

TheHUG
Citizen
Posts: 51
Joined: Sun Apr 01, 2018 4:21 pm

Re: What is setUserData and why do I need it?

Post by TheHUG » Sat Jul 13, 2019 5:47 pm

pgimeno wrote:
Sat Jul 13, 2019 9:41 am
ivan wrote:
Sat Jul 13, 2019 3:32 am
But then you have to modify the table every time a body is created or destroyed.
As for creation, in the other method you have to setUserData anyway, so there's no significant advantage - both methods require an action at creation time. As for destruction, weak tables take care of that automatically. The only extra work is a one-time setup of the weak table.

So for example:

Code: Select all

local bodyData = setmetatable({}, {__mode = 'k'})

function createBody(x, y, extradata)
  local body = love.physics.newBody(world, x, y)
  bodyData[body] = extradata -- instead of body:setUserData(extradata)
  return body
end
As an extra bonus, bodyData is not accessible from other threads so you can't get crashes as you do with setUserData if used from another thread. It can also be hidden from user code, so it can be used in libraries transparently.

As another extra bonus, this method is usable with any object, not just physics objects.
The multithreading thing is a pretty big deal if you need good performance, I just don't like the extra shared state in bodyData, but if you keep the module its used in small and encapsulate it neatly, it should work out smoothly anyway. I'll think about doing that for my own physics library wrapper maybe.

User avatar
raidho36
Party member
Posts: 1804
Joined: Mon Jun 17, 2013 12:00 pm

Re: What is setUserData and why do I need it?

Post by raidho36 » Sat Jul 13, 2019 9:33 pm

ivan wrote:
Sat Jul 13, 2019 11:09 am
Also, I tried the weak table technique and it didn't work as expected.
Weak keys are collected almost right away regardless of whether the bodies are destroyed or not.
Make sure your weak keys and weak values have strong references elsewhere. If their only references are weak ones, they're counted as garbage.

Post Reply

Who is online

Users browsing this forum: Exabot [Bot] and 7 guests