Utils = {} function Utils:CreateAndAttachWeapon(weaponName, weaponVal, coords, playerPed, isOtherPlayer) if not isOtherPlayer and Sling.currentAttachedAmount >= Config.MaxWeaponsAttached then Debug("warn", "Max weapons attached reached") return false end if not weaponVal or not weaponVal.name then Debug("error", "Invalid weapon data") return false end -- Initialize the cached attachments for this weapon if it doesn't exist if not Sling.cachedAttachments[weaponName] then Sling.cachedAttachments[weaponName] = {} end local weaponObject = CreateWeaponObject(weaponVal.name, 0, coords.coords.x, coords.coords.y, coords.coords.z, true, 1.0, 0) if not weaponObject then Debug("error", "Failed to create weapon object") return false end if NetworkGetEntityIsNetworked(weaponObject) then NetworkUnregisterNetworkedEntity(weaponObject) end SetEntityCollision(weaponObject, false, false) if not isOtherPlayer and Config.UseWeaponAttachments then weaponVal.attachments = Inventory:GetWeaponAttachment(weaponName) end for _, component in pairs(weaponVal.attachments or {}) do GiveWeaponComponentToWeaponObject(weaponObject, component) end lib.requestModel(weaponVal.model) local placeholder = CreateObjectNoOffset(weaponVal.model, coords.coords.x, coords.coords.y, coords.coords.z, true, true, false) SetEntityCollision(placeholder, false, false) SetEntityAlpha(placeholder, 0, false) local boneIndex = GetPedBoneIndex(playerPed, (coords.boneId or DEFAULT_BONE)) AttachEntityToEntity(placeholder, playerPed, boneIndex, coords.coords.x, coords.coords.y, coords.coords.z, coords.rot.x, coords.rot.y, coords.rot.z, true, true, false, true, 2, true) AttachEntityToEntity(weaponObject, placeholder, GetEntityBoneIndexByName(placeholder, "gun_root"), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, true, true, false, true, 2, true) Sling.cachedAttachments[weaponName].obj = weaponObject Sling.cachedAttachments[weaponName].placeholder = placeholder if not isOtherPlayer then Sling.currentAttachedAmount = Sling.currentAttachedAmount + 1 end SetModelAsNoLongerNeeded(weaponVal.model) return true end function Utils:DeleteWeapon(weaponName) if not Sling.cachedAttachments[weaponName] then return end local attachment = Sling.cachedAttachments[weaponName] if attachment.obj and DoesEntityExist(attachment.obj) then if NetworkGetEntityIsNetworked(attachment.obj) then NetworkUnregisterNetworkedEntity(attachment.obj) end DeleteObject(attachment.obj) end if attachment.placeholder then if IsEntityAttachedToAnyPed(attachment.placeholder) then DetachEntity(attachment.placeholder, true, false) end if DoesEntityExist(attachment.placeholder) then DeleteObject(attachment.placeholder) end end Sling.cachedAttachments[weaponName] = nil -- Nur verringern, wenn es keine Waffe eines anderen Spielers ist if not string.find(weaponName, '_') then Sling.currentAttachedAmount = math.max(0, Sling.currentAttachedAmount - 1) end end function Utils:Debug(type, message) if not Config.Debug then return end if type == "error" then print("^1[ERROR] " .. message .. "^7") elseif type == "success" then print("^2[SUCCESS] " .. message .. "^7") elseif type == "info" then print("^5[INFO] " .. message .. "^7") elseif type == "warn" then print("^3[WARN] " .. message .. "^7") end end function Utils:Round(num, numDecimalPlaces) local mult = 10^(numDecimalPlaces or 0) return math.floor(num * mult + 0.5) / mult end function Utils:TableContains(table, element) for _, value in pairs(table) do if value == element then return true end end return false end function Utils:GetTableLength(table) local count = 0 for _ in pairs(table) do count = count + 1 end return count end function Utils:DeepCopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[Utils:DeepCopy(orig_key)] = Utils:DeepCopy(orig_value) end setmetatable(copy, Utils:DeepCopy(getmetatable(orig))) else copy = orig end return copy end function Utils:MergeTable(t1, t2) for k, v in pairs(t2) do if type(v) == "table" and type(t1[k] or false) == "table" then Utils:MergeTable(t1[k], t2[k]) else t1[k] = v end end return t1 end function Utils:GetDistance(coords1, coords2) return #(coords1 - coords2) end function Utils:DrawText3D(coords, text) local onScreen, _x, _y = World3dToScreen2d(coords.x, coords.y, coords.z) local px, py, pz = table.unpack(GetGameplayCamCoords()) local dist = #(vector3(px, py, pz) - coords) local scale = (1 / dist) * 2 local fov = (1 / GetGameplayCamFov()) * 100 local scale = scale * fov if onScreen then SetTextScale(0.0 * scale, 0.55 * scale) SetTextFont(0) SetTextProportional(1) SetTextColour(255, 255, 255, 255) SetTextDropshadow(0, 0, 0, 0, 255) SetTextEdge(2, 0, 0, 0, 150) SetTextDropShadow() SetTextOutline() SetTextEntry("STRING") SetTextCentre(1) AddTextComponentString(text) DrawText(_x,_y) end end function Utils:LoadAnimDict(dict) while not HasAnimDictLoaded(dict) do RequestAnimDict(dict) Wait(5) end end function Utils:PlayAnim(ped, dict, anim, settings) if not settings then settings = {} end Utils:LoadAnimDict(dict) TaskPlayAnim(ped, dict, anim, settings.blendInSpeed or 3.0, settings.blendOutSpeed or 3.0, settings.duration or -1, settings.flag or 49, settings.playbackRate or 0, settings.lockX or false, settings.lockY or false, settings.lockZ or false ) RemoveAnimDict(dict) end function Utils:CreateBlip(coords, sprite, color, text, scale, category) local blip = AddBlipForCoord(coords.x, coords.y, coords.z) SetBlipSprite(blip, sprite) SetBlipDisplay(blip, 4) SetBlipScale(blip, scale or 0.8) SetBlipColour(blip, color) SetBlipAsShortRange(blip, true) if category then SetBlipCategory(blip, category) end BeginTextCommandSetBlipName("STRING") AddTextComponentString(text) EndTextCommandSetBlipName(blip) return blip end function Utils:DrawMarker(type, coords, size, color, bobUpAndDown) DrawMarker( type, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, size.x, size.y, size.z, color.r, color.g, color.b, color.a, false, bobUpAndDown or false, 2, false, nil, nil, false ) end