attached_ped = {}
attached_bone = {}
attached_x = {}
attached_y = {}
attached_z = {}
attached_rx = {}
attached_ry = {}
attached_rz = {}

function attachElementToBone(element, ped, bone, x, y, z, rx, ry, rz)
	if (not (isElement(element) and isElement(ped))) or (getElementType(ped) ~= "ped" and getElementType(ped) ~= "player") then
		return false
	end
	
	bone = tonumber(bone)
	
	if not bone or bone < 1 or bone > 20 then
		return false
	end
	
	x, y, z, rx, ry, rz = tonumber(x) or 0, tonumber(y) or 0, tonumber(z) or 0, tonumber(rx) or 0, tonumber(ry) or 0, tonumber(rz) or 0
	
	attached_ped[element] = ped
	attached_bone[element] = bone
	attached_x[element] = x
	attached_y[element] = y
	attached_z[element] = z
	attached_rx[element] = rx
	attached_ry[element] = ry
	attached_rz[element] = rz
	
	if setElementCollisionsEnabled then
		setElementCollisionsEnabled(element,false)
	end
	
	if isFromServerSide then
		triggerClientEvent(getRootElement(), "attachElementToBone", getRootElement(), element, ped, bone, x, y, z, rx, ry, rz)
	end
	
	return true
end

function detachElementFromBone(element)
	if not element or not attached_ped[element] then
		return false
	end
	
	clearAttachmentData(element)
	
	if setElementCollisionsEnabled then
		setElementCollisionsEnabled(element,true)
	end
	
	if isFromServerSide then
		triggerClientEvent(getRootElement(), "detachElementFromBone", getRootElement(), element)
	end
	
	return true
end

function isElementAttachedToBone(element)
	if not element then
		return false
	end
	
	return isElement(attached_ped[element])
end

function getElementBoneAttachmentDetails(element)
	if not isElementAttachedToBone(element) then
		return false
	end
	
	return attached_ped[element], attached_bone[element], attached_x[element], attached_y[element], attached_z[element], attached_rx[element], attached_ry[element], attached_rz[element]
end

function setElementBonePositionOffset(element, x, y, z)
	local ped, bone, ox, oy, oz, rx, ry, rz = getElementBoneAttachmentDetails(element)
	
	if not ped then
		return false
	end
	
	return attachElementToBone(element, ped, bone, x, y, z, rx, ry, rz)
end

function setElementBoneRotationOffset(element, rx, ry, rz)
	local ped, bone, x, y, z, ox, oy, oz = getElementBoneAttachmentDetails(element)
	
	if not ped then
		return false
	end
	
	return attachElementToBone(element, ped, bone, x, y, z, rx, ry, rz)
end

if not isFromServerSide then
	function getBonePositionAndRotation(ped, bone)
		bone = tonumber(bone)
		
		if not bone or bone < 1 or bone > 20 then
			return false
		end
		
		if not isElement(ped) or (getElementType(ped) ~= "player" and getElementType(ped) ~= "ped") or not isElementStreamedIn(ped) then
			return false
		end
		
		local x, y, z = getPedBonePosition(ped, bone_0[bone])
		local rx, ry, rz = getEulerAnglesFromMatrix(getBoneMatrix(ped, bone))
		
		return x, y, z, rx, ry, rz
	end
end

function clearAttachmentData(element)
	attached_ped[element] = nil
	attached_bone[element] = nil
	attached_x[element] = nil
	attached_y[element] = nil
	attached_z[element] = nil
	attached_rx[element] = nil
	attached_ry[element] = nil
	attached_rz[element] = nil
end

function forgetDestroyedElements()
	if not attached_ped[source] then
		return
	end
	
	clearAttachmentData(source)
end
addEventHandler(isFromServerSide and "onElementDestroy" or "onClientElementDestroy", getRootElement(), forgetDestroyedElements)

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