JeViCo

I need a little advice with metatables

Recommended Posts

Hello everyone :3

I tried to make my own dx-gui system. I separate functions into several .lua files (i have a window and a button)

So i used this to destroy elements in 3-rd file 

addEventHandler("onClientElementDestroy",root,function()
	if getElementData(source,"dxcore") == true then
		triggerEvent("destroy-"..getElementType(source),localPlayer,getElementData(source,"variable-data"))
	end
end)

-- getElementData(source,"variable-data") returns table (all info about this dx element in metatable)

1-st file:

function JVbutton:destroy()
	-- remove stuff (button)
end

addEvent("destroy-dx-button",true)
addEventHandler("destroy-dx-button",root,function(data)
	data:destroy()
end)

2-nd file

function JVwindow:destroy()
	-- remove stuff (window)
end

addEvent("destroy-dx-window",true)
addEventHandler("destroy-dx-window",root,function(data)
	data:destroy()
end)

but i keep getting same errors: ( attempt to call method 'destroy' a nil value)

What am i doing wrong?

Edited by JeViCo

Share this post


Link to post

Ever seen a meta table as they are created? A meta table is used to change the behaviour of a regular table. The main issue is with the fact that it uses functions to achieve this behaviour.

 

 

And functions...

Optional Arguments

NOTE: When using optional arguments, you might need to supply all arguments before the one you wish to use. For more information on optional arguments, see optional arguments.

    sendTo: The event will be sent to all players that are children of the specified element. By default this is the root element, and hence the event is sent to all players. If you specify a single player it will just be sent to that player. This argument can also be a table of player elements.
    arguments...: A list of arguments to trigger with the event. You can pass any lua data type (except functions). You can also pass elements.

https://wiki.multitheftauto.com/wiki/TriggerClientEvent

 

...can't be send over according to wiki.

But even if this is a meta table, you will have the same problem with a regular table.

 

This has probably happend: all the functions that are inside of the table are deleted.

 

Edited by IIYAMA
  • Thanks 1

Share this post


Link to post
On 07/11/2018 at 19:17, IIYAMA said:

This has probably happend: all the functions that are inside of the table are deleted.

I checked my code and that's true - all data saved except for functions

i'll try to rewrite functions using elements only and connect them with metatables with elementData

  • Like 1

Share this post


Link to post

@IIYAMA same problem idk why

1-st lua file

function destroyDX(element)
	local dx_type = getElementType(element)
	if dx_type == "dx-window" then
		JVwindow.destroy(source)
	elseif dx_type == "dx-button" then
	
	end
end

addEventHandler("onClientElementDestroy",root,function()
	if getElementData(source,"dxcore") == true then
		cancelEvent()
		destroyDX(source)
	end
end)

2-nd lua file

function JVwindow.destroy(element)
	local dat = getElementData(element, "variable-data")
	
	if #dat.main.related_elements > 0 then
		for _, el in ipairs(dat.main.related_elements) do
			destroyElement(el)
		end
	end
	
	removeEventHandler("onClientRender", root, dat.handlers.render)
	setmetatable(dat, nil)
	destroyElement(element)
end

errors:

wrokb2iYSveqwZxyRuW4FA.png

I thought cancelEvent() didn't work but nope

print(element) returns userdata so element exists

Share this post


Link to post
4 minutes ago, IIYAMA said:

Image not working.

What do you mean? It removed function once and spams now or what?

Share this post


Link to post

@IIYAMA i returned :3 i figured everything out except for one:

i use onClientRender event to draw DX window like that

wnd.handlers.render = function() wnd:renderWindow() end
addEventHandler("onClientRender", element, wnd.handlers.render)

setElementData(element,"variable-data",wnd)

but i can't do this because all functions disappear

local dat = getElementData(source, "variable-data")
removeEventHandler("onClientRender", root, dat.handlers.render)

i don't know how to save them. Maybe i should not use elementData

Share this post


Link to post

sorry for bothering you :с i solved this problem by using an additional table

Share this post


Link to post

now i have another problem :c elements don't want to destroy. I use destroyElement(window) then onClientElementDestroy triggers where i do some magic stuff and that's all. window variable is still userdata so element still exists 😕 or something wrong with my code

Share this post


Link to post
33 minutes ago, JeViCo said:

now i have another problem :c elements don't want to destroy. I use destroyElement(window) then onClientElementDestroy triggers where i do some magic stuff and that's all. window variable is still userdata so element still exists 😕 or something wrong with my code

After you destroyed an element. A saved userdata reference will remain inside of the Lua memory.

A userdata reference is not an element itself. It is a value that can be used to refer to an element in MTA.

------

It is like having a cat which you named `miauw`. After it died of old age, you can still refer to your precious cat by calling it's name.

`miauw` I have dinner for you! (calling function: giveCatFoot(cat))

And then your grandma reminds you of the fact that it has already died...  (warning: element does not exist)

-------

That is sort of how userdata references work.

 

 

See function isElement for userdata validation.

isElement

 

Edited by IIYAMA
  • Thanks 1
  • Haha 1

Share this post


Link to post

thank you for your support 😁 i had some problems with my code. Now everything works amazing

  • Like 1

Share this post


Link to post

For the sake of god, dont use element data
If possible avoid it, it's slow af.(indexing is 30x times faster if I recall correctly)

Share this post


Link to post
7 hours ago, Pirulax said:

For the sake of god, dont use element data
If possible avoid it, it's slow af.(indexing is 30x times faster if I recall correctly)

That really depends how you compare and use it.

1 on 1, sure it can be 30x faster. But aren't you comparing two different things? A function vs just an empty variable.

If you take a look at dxDraw functions, it is obvious that they are being called every frame. Incompare to call getElementData there isn't much of a difference. The data is bound to the element, it is not like you have to search in all elementdata for it.

Example: You use 60 dx functions each frame and 1 time a getElementData function. How much will we gain from optimize this function?

 

The real danger of elementdata is in using it, without knowing what mechanisms are activated behind it, after it is SET.

 

Share this post


Link to post

Well, setting takes way more time than getting it, just because the :~ty way its implemented in.
for some reason everything is in CStaticFunctionDefinitions.cpp, even those things which are  CLASS specific, for example, when you set an element data a new value, you'd expect that the CCustomData class should send a packet to the client to request them to refresh their data, but... NO, it doesn't.
And that's not a big of a deal, at all..
But, take a look at the way setElementData is implemented...

Share this post


Link to post

Element data is not that bad when used properly; for a beginner when used with caution element data is just fine. That being said; in the future it's better to make your own element data system to improve performance when systems needing element data start growing.

Edited by CodyJ(L)

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.