Jump to content

bone_attach - performance


majqq

Recommended Posts

Hey. I would like to integrate bone attach with my gamemode, and also improve code a bit.

First of all, question about meta of bone attach.

<script src="bone_attach.lua" />
<script src="bone_attach_c.lua" type="client" cache="false" />
<script src="attach_func.lua" />
<script src="attach_func.lua" type="client" cache="false" />
<script src="bone_pos_rot.lua" type="client" cache="false" />

If script doesn't have defined type, then by default it's server/shared?

So i thought about those ways.

1. Use more locals - following this performance tips?

2. Replace onClientRender to render events by IIYAMA - probably this should help a little bit though.

3. Any other way which i don't know about?

 

Link to post
8 hours ago, majqq said:

If script doesn't have defined type, then by default it's server/shared?

server by default.

 

 

8 hours ago, majqq said:

3. Any other way which i don't know about?

A critical one:

Loop over an array table structure. Not an object table structure.

But that doesn't mean you can't use both.

 

local boneAttachments_array = {}
local boneAttachments_object = {}

 

local newAttachment = {
	posX,
	posY,
  	ped -- etc.
}


boneAttachments_array[#boneAttachments_array + 1] = newAttachment
boneAttachments_object[ped] = newAttachment

 

Access the (same) data:

for i=1, #boneAttachments_array do
	local boneAttachment = boneAttachments_array[i]
end

 

local boneAttachment = boneAttachments_object[ped]

 

 

  • Like 1
Link to post
6 hours ago, IIYAMA said:

server by default.

 

 

A critical one:

Loop over an array table structure. Not an object table structure.

But that doesn't mean you can't use both.

 


local boneAttachments_array = {}
local boneAttachments_object = {}

 


local newAttachment = {
	posX,
	posY,
  	ped -- etc.
}


boneAttachments_array[#boneAttachments_array + 1] = newAttachment
boneAttachments_object[ped] = newAttachment

 

Access the (same) data:


for i=1, #boneAttachments_array do
	local boneAttachment = boneAttachments_array[i]
end

 


local boneAttachment = boneAttachments_object[ped]

 

 

Where exactly i should use int loop, or we're about changing it in this function?

function forgetNonExistingPeds()
	local checkedcount = 0
	while true do
		for element,ped in pairs(attached_ped) do
			if not isElement(ped) then clearAttachmentData(element) end
			checkedcount = checkedcount+1
			if checkedcount >= 1000 then
				coroutine.yield()
				checkedcount = 0
			end
		end
		coroutine.yield()
	end
end

 

Link to post
1 hour ago, majqq said:

Where exactly i should use int loop, or we're about changing it in this function?


function forgetNonExistingPeds()
	local checkedcount = 0
	while true do
		for element,ped in pairs(attached_ped) do
			if not isElement(ped) then clearAttachmentData(element) end
			checkedcount = checkedcount+1
			if checkedcount >= 1000 then
				coroutine.yield()
				checkedcount = 0
			end
		end
		coroutine.yield()
	end
end

 

 

At places with this kind of loops:

for element,ped in pairs(attached_ped) do

 

If you want to optimise this, it will take at least an hour to implement the new table structure. Ask yourself the question: "Do you want to spend your time on that?"

 

Also the code from your previous reply could be merged with:

Spoiler

function putAttachedElementsOnBones()
	for element,ped in pairs(attached_ped) do
		if not isElement(element) then
			clearAttachmentData(element)
		elseif isElementStreamedIn(ped) then
			local bone = attached_bone[element]
			local x,y,z = getPedBonePosition(ped,bone_0[bone])
			local xx,xy,xz,yx,yy,yz,zx,zy,zz = getBoneMatrix(ped,bone)
			local offx,offy,offz = attached_x[element],attached_y[element],attached_z[element]
			local offrx,offry,offrz = attached_rx[element],attached_ry[element],attached_rz[element]
			local objx = x+offx*xx+offy*yx+offz*zx
			local objy = y+offx*xy+offy*yy+offz*zy
			local objz = z+offx*xz+offy*yz+offz*zz
			local rxx,rxy,rxz,ryx,ryy,ryz,rzx,rzy,rzz = getMatrixFromEulerAngles(offrx,offry,offrz)

			local txx = rxx*xx+rxy*yx+rxz*zx
			local txy = rxx*xy+rxy*yy+rxz*zy
			local txz = rxx*xz+rxy*yz+rxz*zz
			local tyx = ryx*xx+ryy*yx+ryz*zx
			local tyy = ryx*xy+ryy*yy+ryz*zy
			local tyz = ryx*xz+ryy*yz+ryz*zz
			local tzx = rzx*xx+rzy*yx+rzz*zx
			local tzy = rzx*xy+rzy*yy+rzz*zy
			local tzz = rzx*xz+rzy*yz+rzz*zz
			offrx,offry,offrz = getEulerAnglesFromMatrix(txx,txy,txz,tyx,tyy,tyz,tzx,tzy,tzz)
			if (string.find(objx..objy..objz, "a")) then
			  setElementPosition(element, x, y, z)
			else
			  setElementPosition(element, objx, objy, objz)
			end
			if (not string.find(offrx..offry..offrz, "a")) then
			  setElementRotation(element, offrx, offry, offrz, "ZXY")
		else
			setElementPosition(element,getElementPosition(ped))
			end
		end
	end
end
addEventHandler("onClientPreRender",root,putAttachedElementsOnBones)

 

 

 

 

  • Like 1
Link to post
1 hour ago, IIYAMA said:

 

At places with this kind of loops:


for element,ped in pairs(attached_ped) do

 

If you want to optimise this, it will take at least an hour to implement the new table structure. Ask yourself the question: "Do you want to spend your time on that?"

 

Also the code from your previous reply could be merged with:

  Hide contents


 
function putAttachedElementsOnBones()
	for element,ped in pairs(attached_ped) do
		if not isElement(element) then
			clearAttachmentData(element)
		elseif isElementStreamedIn(ped) then
			local bone = attached_bone[element]
			local x,y,z = getPedBonePosition(ped,bone_0[bone])
			local xx,xy,xz,yx,yy,yz,zx,zy,zz = getBoneMatrix(ped,bone)
			local offx,offy,offz = attached_x[element],attached_y[element],attached_z[element]
			local offrx,offry,offrz = attached_rx[element],attached_ry[element],attached_rz[element]
			local objx = x+offx*xx+offy*yx+offz*zx
			local objy = y+offx*xy+offy*yy+offz*zy
			local objz = z+offx*xz+offy*yz+offz*zz
			local rxx,rxy,rxz,ryx,ryy,ryz,rzx,rzy,rzz = getMatrixFromEulerAngles(offrx,offry,offrz)

			local txx = rxx*xx+rxy*yx+rxz*zx
			local txy = rxx*xy+rxy*yy+rxz*zy
			local txz = rxx*xz+rxy*yz+rxz*zz
			local tyx = ryx*xx+ryy*yx+ryz*zx
			local tyy = ryx*xy+ryy*yy+ryz*zy
			local tyz = ryx*xz+ryy*yz+ryz*zz
			local tzx = rzx*xx+rzy*yx+rzz*zx
			local tzy = rzx*xy+rzy*yy+rzz*zy
			local tzz = rzx*xz+rzy*yz+rzz*zz
			offrx,offry,offrz = getEulerAnglesFromMatrix(txx,txy,txz,tyx,tyy,tyz,tzx,tzy,tzz)
			if (string.find(objx..objy..objz, "a")) then
			  setElementPosition(element, x, y, z)
			else
			  setElementPosition(element, objx, objy, objz)
			end
			if (not string.find(offrx..offry..offrz, "a")) then
			  setElementRotation(element, offrx, offry, offrz, "ZXY")
		else
			setElementPosition(element,getElementPosition(ped))
			end
		end
	end
end
addEventHandler("onClientPreRender",root,putAttachedElementsOnBones)

 

 

 

 

I would try, i'm sure by following your advice i could do that :P

I just need a point to start off, and some more time (besides that, i'm doing a lot of other things, i'm asking about that, because i will need it in nearest future.)

Link to post
  • 3 months later...

Hey @IIYAMA

Each day, with small steps am getting closer to that.

But before i am going to start optimizing bone_attach, i want to be sure that i've optimized my other scripts correctly.

This refers to Lua functions and MTA functions which are in _G table?

So for example math. functions, tostring, tonumber, and shared functions which are available in client and server side aswell (getElementsByType, getElementPosition) ?

I'm just asking because after testing localized things it gives me a different result (less or more ticks)

Link to post

 

28 minutes ago, majqq said:

This refers to Lua functions and MTA functions which are in _G table?

The _G table keeps track of all global variables. Not just functions and not all functions, as some can be saved in local variables.

https://www.Lua.org/pil/14.html

 

 

31 minutes ago, majqq said:

So for example math. functions, tostring, tonumber, and shared functions which are available in client and server side aswell (getElementsByType, getElementPosition) ?

Yes, they are `shared` or rather copied.

 

I honestly only localize my own functions. The last time I checked, I didn't notice any optimization by localize MTA functions. Every file has it's own scope, so making use of that is not a bad thing. My main reason for localization: You can use it to distinguish functions used within the file, from functions that are called from other files.

 

The only thing I do with some Lua functions is this:

local mathRandom = math.random

 

  • Like 1
Link to post
5 hours ago, IIYAMA said:

 

The _G table keeps track of all global variables. Not just functions and not all functions, as some can be saved in local variables.

https://www.Lua.org/pil/14.html

 

 

Yes, they are `shared` or rather copied.

 

I honestly only localize my own functions. The last time I checked, I didn't notice any optimization by localize MTA functions. Every file has it's own scope, so making use of that is not a bad thing. My main reason for localization: You can use it to distinguish functions used within the file, from functions that are called from other files.

 

The only thing I do with some Lua functions is this:


local mathRandom = math.random

 

Hi, thanks for answer. I've checked by myself and probably it worked for Lua functions (looks like), but for some reason on MTA functions it showed mostly less or rarely - more ticks, there was a few times when it taked even more than non-localized things. (maybe fault of fast restart of script but i don't think so).

  • Like 1
Link to post
11 hours ago, majqq said:

but for some reason on MTA functions it showed mostly less or rarely - more ticks, there was a few times when it taked even more than non-localized things.

I had the same results, so nothing has changed. It might even be possible that they are already localized in some unknown way. Just as the predefined source variable is localized when an event has been triggered.

  • Like 1
Link to post
  • 2 weeks later...
On 19/08/2019 at 17:28, IIYAMA said:

I had the same results, so nothing has changed. It might even be possible that they are already localized in some unknown way. Just as the predefined source variable is localized when an event has been triggered.

Hey @IIYAMA

Probably i've finished this.

I just need to fix rotation, and test server-side.

But at the moment, i've tested it only by myself, with 1 attached object.

This is the result:

sHPNbQG.png

- Localized Lua functions, tables, and any other functions which returns data.

- Used int loop instead of pairs, didn't took me so long since i'm practising tables from the time when you showed me how to sync data between server/client.

- With thing above i get rid of timer, coroutine and while loop. (hopefully this will fix an annoying error, i check if element actually exists, if not, script removing it from table)

Glad that you helped me ;)

Edited by majqq
Link to post
2 hours ago, majqq said:

This is the result:

And what was it before? If you want to measure this correctly you need multiple samples. 0 AttachElements (idle). 10 AttachElements (doing something). 1000 AttachElements (doing a lot). 10000 AttachElements (doing too much).

Link to post
2 hours ago, IIYAMA said:

And what was it before? If you want to measure this correctly you need multiple samples. 0 AttachElements (idle). 10 AttachElements (doing something). 1000 AttachElements (doing a lot). 10000 AttachElements (doing too much).

Sorry but i didn't last 60 seconds at last test, at 1000 objects :P

Screenshot comparing old one and new one, running at same time.

1 object:

k7aDxNx.png

10 objects:

mG1uL8K.png

100 objects:

ANSBzll.png

1000 objects:

rflF5Sy.png

  • Like 1
Link to post

@Einheit-101

If we keep looping out of it and only talk about indexing.

 

This below is just an assumption:

If this is the userdata key: (which is at the very end just a complex and unique identifier.)

"userdata-324ftfdbgfd"

 

And this is the data:

table = {
	["userdata-424ftfsdgsf"] = true,
	["userdata-3sd3524ftfd"] = true,
	["userdata-325524ftfdb"] = true,
	["userdata-324ftfdbgfd"] = true
}

 

Depending on which algorithm is used, the search time variates. (algorithm < which I have no knowledge of)

But if I would program this search, I might do it like this in my first try:

I know already the type, so my start would be: "userdata-"

>>>

userdata-424ftfsdgsf
userdata-3sd3524ftfd
userdata-325524ftfdb
userdata-324ftfdbgfd

Collect all items with userdata. steps * items

>>>

userdata-424ftfsdgsf
userdata-3sd3524ftfd
userdata-325524ftfdb
userdata-324ftfdbgfd

print(string.byte("3")) -- 51

+ update position * 4 + 4 steps

>>>


userdata-3sd3524ftfd
userdata-325524ftfdb
userdata-324ftfdbgfd

print(string.byte("s")) -- 115
print(string.byte("2")) -- 50

+ update position * 3 + 3 steps

>>>

print(string.byte("4")) -- 52


userdata-325524ftfdb
userdata-324ftfdbgfd < found item in table

+ update position *  2 + 2 steps

 

Lua would probably be better in this then I do. But this has multiple search steps in it, no matter what kind of algorithm you use.

 


 

table = {
	true, -- 1
	true, -- 2
	true, -- 3
	true -- 4
}

table = {
	[1] = true,
	[2] = true,
	[3] = true,
	[4] = true
}

 

Finding the index in this kind of table should be technically be faster based on two ways.

  1. Position of the characters do not matter. It is a single value, the cpu knows very well how to work with that.
    As with user-data's/strings, not only the position matters, the value is also different:
    print(string.byte("a")) -- 97

    Much complexer values X position.

  2. Everything is already placed in order if you keep the table as an clean array.
    Just as with cleaning your room. After the cleaning, you do not have to look everywhere in your room. You more or less know where to find what and how many things you have of it.

 

Searching for item 4?

no, no, no, yes

(4 steps)

 


 

Note: looping to find an item VS using a custom key to find an item is a different subject.

 


 

If somebody knows how this really works, then that would be nice fun facts.

 

 

 

 

 

 

 

Edited by IIYAMA
  • Thanks 2
Link to post
  • 5 months later...
12 hours ago, iDannz [Breno] said:

maybe isElementOnScreen can help in pre render event

Thanks for suggestion, but i already tested isElementOnScreen, it would cause object stay for a moment when not looking on it. However this was so far ago, so i might did something incorrect. Whatsoever performance in render can be improved by declaring variables out of rendering scope (so basically in main one), and reusing them. I will rewrite bone attach once again to apply some tricks what i've learnt since this topic (to gain even more than 50% performance boost), and let you know about results in this topic :)

Edited by majqq
Link to post
31 minutes ago, majqq said:

Thanks for suggestion, but i already tested isElementOnScreen, it would cause object stay for a moment when not looking on it. However this was so far ago, so i might did something incorrect. Whatsoever performance in render can be improved by declaring variables out of rendering scope (so basically in main one), and reusing them. I will rewrite bone attach once again to apply some tricks what i've learnt since this topic (to gain even more than 50% performance boost), and let you know about results in this topic :)

I also got good results, this is the performance I got with 100 objects:

100 objects (looking directly at them):
vqhQ8wF.png

100 objects (without looking at them):
(I didn't notice any apparent problems when using isElementOnScreen, maybe I'll be back to test it soon)

nDEIOVn.png

 

I would like to thank you and everyone who commented here, as this topic inspired me to learn a little more about optimization in Lua :D

Edited by iDannz [Breno]
  • Like 1
Link to post
30 minutes ago, XaskeL said:

I caught trend and I'm working on optimize bone_attach.

And what did you say? Do you want to share it with me? 😅 😅

And I don't have to do it too?

Link to post
38 minutes ago, Patrick said:

And what did you say? Do you want to share it with me? 😅 😅

And I don't have to do it too?

I want put out it on github. If you add server events and some functions for exports, then we can give people a good enough bone_attach

Link to post
2 hours ago, XaskeL said:

I want put out it on github. If you add server events and some functions for exports, then we can give people a good enough bone_attach

I'm  in.

Link to post
  • 1 month later...

Hi. So after all i've decided to play with bone attach once again, had to fix CJ skin bug, and decided to squeeze out even more performance :D

CPU: i5-9400F

1 attached object:

rInLtje.png

100 attached objects:

VNMPMCC.png

 

  • Like 1
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.

×
×
  • Create New...