local sincos = require("glm").sincos local rad = require("glm").rad local abs = math.abs local getCamCoords = GetFinalRenderedCamCoord local getCamRot = GetFinalRenderedCamRot local getEntityCoords = GetEntityCoords local disableControls = DisableAllControlActions local drawLine = DrawLine local getCamMatrix = GetCamMatrix local createCamera = Utils.CreateCamera local handleFlyCam = Utils.HandleFlyCam local drawScaleform = Utils.DrawScaleform raycast = { cameraOptions = { controls = { "up", "right", "forward" } } } function raycast.getForwardVector(self) local camRot = getCamRot(2) local sinResult, cosResult = sincos(rad(camRot)) return vec3( -sinResult.z * abs(cosResult.x), cosResult.z * abs(cosResult.x), sinResult.x ) end function raycast.gameplayCamera(self, callback, options, flags) assert(type(callback) == "function", "raycast:gameplayCamera ::: fn must be a function") options = options or {} self.controls = Utils.GetControls(options) self.scaleform = Utils.CreateInstructional(self.controls) self.active = true if not flags then flags = 17 end while self.active do DisablePlayerFiring(cache.playerId, true) local camPos = getCamCoords() local forward = self:getForwardVector() * 50.0 local endPos = camPos + forward local rayHandle = StartExpensiveSynchronousShapeTestLosProbe( camPos.x, camPos.y, camPos.z, endPos.x, endPos.y, endPos.z, flags, cache.ped, 4 ) local pedPos = getEntityCoords(cache.ped) local _, hitResult, hitCoords, _, hitEntity = GetShapeTestResultIncludingMaterial(rayHandle) self.coords = hitCoords self.entity = (hitEntity ~= 0 and hitEntity) or nil self.hit = (hitResult == 1) if self.hit then DrawMarker(28, self.coords.x, self.coords.y, self.coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.2, 0.2, 255, 42, 24, 100, false, false, 0, true, false, false, false ) drawLine( pedPos.x, pedPos.y, pedPos.z, self.coords.x, self.coords.y, self.coords.z, 255, 42, 24, 100 ) end callback(self) drawScaleform(self.scaleform) self.lastCoords = self.coords Wait(0) end end function raycast.freeCamera(self, callback, extraControls) assert(type(callback) == "function", "raycast:camera ::: fn must be a function") local _, forward, _, origin = GetEntityMatrix(cache.ped) local camPos = origin + forward * 2 local camRot = GetEntityRotation(cache.ped) self.camRot = camRot self.camPos = camPos self.camera = createCamera("DEFAULT_SCRIPTED_CAMERA", camPos, camRot, true) self.active = true SetPlayerControl(cache.playerId, false, 0) local allControls = table.deepclone(self.cameraOptions.controls) if extraControls then for _, ctrl in pairs(extraControls) do allControls[#allControls + 1] = ctrl end end self.controls = Utils.GetControls(allControls) self.scaleform = Utils.CreateInstructional(self.controls) while self.active do disableControls(0) self.camPos, self.camRot = handleFlyCam(self.camera) local _, rightVec, _, _ = getCamMatrix(self.camera) local endPos = vec3( self.camPos.x + rightVec.x * 100.0, self.camPos.y + rightVec.y * 100.0, self.camPos.z + rightVec.z * 100.0 ) local rayHandle = StartExpensiveSynchronousShapeTestLosProbe( self.camPos.x, self.camPos.y, self.camPos.z, endPos.x, endPos.y, endPos.z, 17, cache.ped, 4 ) local _, _, hitCoords, _, hitEntity = GetShapeTestResultIncludingMaterial(rayHandle) self.coords = hitCoords self.entity = hitEntity self.hit = (hitResult == 1) local cx, cy, cz = self.coords.x, self.coords.y, self.coords.z drawLine(cx - 0.3, cy, cz, cx + 0.3, cy, cz, 255, 0, 0, 255) drawLine(cx, cy, cz, cx, cy, cz + 0.3, 255, 0, 0, 255) drawLine(cx, cy - 0.3, cz, cx, cy + 0.3, cz, 255, 0, 0, 255) drawScaleform(self.scaleform) callback(self) Wait(0) end end function raycast.destroy(self) self.active = false if self.camera then Utils.DestroyFlyCam(self.camera, 1000) self.camera = nil SetPlayerControl(cache.playerId, true, 0) end end AddEventHandler("onResourceStop", function(resourceName) if resourceName == GetCurrentResourceName() then raycast:destroy() end end)