349 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
if not LoadResourceFile(cache.resource, 'web/build/index.html') then
 | 
						|
	error('Unable to load UI. Build ox_doorlock or download the latest release.\n	^3https://github.com/overextended/ox_doorlock/releases/latest/download/ox_doorlock.zip^0')
 | 
						|
end
 | 
						|
 | 
						|
if not lib.checkDependency('ox_lib', '3.14.0', true) then return end
 | 
						|
 | 
						|
local function createDoor(door)
 | 
						|
	local double = door.doors
 | 
						|
	door.zone = GetLabelText(GetNameOfZone(door.coords.x, door.coords.y, door.coords.z))
 | 
						|
 | 
						|
	if double then
 | 
						|
		for i = 1, 2 do
 | 
						|
			AddDoorToSystem(double[i].hash, double[i].model, double[i].coords.x, double[i].coords.y, double[i].coords.z, false, false, false)
 | 
						|
			DoorSystemSetDoorState(double[i].hash, 4, false, false)
 | 
						|
			DoorSystemSetDoorState(double[i].hash, door.state, false, false)
 | 
						|
 | 
						|
			if door.doorRate or not door.auto then
 | 
						|
				DoorSystemSetAutomaticRate(double[i].hash, door.doorRate or 10.0, false, false)
 | 
						|
			end
 | 
						|
		end
 | 
						|
	else
 | 
						|
		AddDoorToSystem(door.hash, door.model, door.coords.x, door.coords.y, door.coords.z, false, false, false)
 | 
						|
		DoorSystemSetDoorState(door.hash, 4, false, false)
 | 
						|
		DoorSystemSetDoorState(door.hash, door.state, false, false)
 | 
						|
 | 
						|
		if door.doorRate or not door.auto then
 | 
						|
			DoorSystemSetAutomaticRate(door.hash, door.doorRate or 10.0, false, false)
 | 
						|
		end
 | 
						|
	end
 | 
						|
end
 | 
						|
 | 
						|
local nearbyDoors = {}
 | 
						|
local Entity = Entity
 | 
						|
 | 
						|
lib.callback('ox_doorlock:getDoors', false, function(data)
 | 
						|
	doors = data
 | 
						|
 | 
						|
	for _, door in pairs(data) do
 | 
						|
		createDoor(door)
 | 
						|
	end
 | 
						|
 | 
						|
	while true do
 | 
						|
		table.wipe(nearbyDoors)
 | 
						|
		local coords = GetEntityCoords(cache.ped)
 | 
						|
 | 
						|
		for _, door in pairs(doors) do
 | 
						|
			local double = door.doors
 | 
						|
			door.distance = #(coords - door.coords)
 | 
						|
 | 
						|
			if double then
 | 
						|
				if door.distance < 80 then
 | 
						|
					for i = 1, 2 do
 | 
						|
						if not double[i].entity and IsModelValid(double[i].model) then
 | 
						|
							local entity = GetClosestObjectOfType(double[i].coords.x, double[i].coords.y, double[i].coords.z, 1.0, double[i].model, false, false, false)
 | 
						|
 | 
						|
							if entity ~= 0 then
 | 
						|
								double[i].entity = entity
 | 
						|
								Entity(entity).state.doorId = door.id
 | 
						|
							end
 | 
						|
						end
 | 
						|
					end
 | 
						|
 | 
						|
					if door.distance < 20 then
 | 
						|
						nearbyDoors[#nearbyDoors + 1] = door
 | 
						|
					end
 | 
						|
				else
 | 
						|
					for i = 1, 2 do
 | 
						|
						double[i].entity = nil
 | 
						|
					end
 | 
						|
				end
 | 
						|
			elseif door.distance < 80 then
 | 
						|
				if not door.entity and IsModelValid(door.model) then
 | 
						|
					local entity = GetClosestObjectOfType(door.coords.x, door.coords.y, door.coords.z, 1.0, door.model, false, false, false)
 | 
						|
 | 
						|
					if entity ~= 0 then
 | 
						|
						local min, max = GetModelDimensions(door.model)
 | 
						|
						local points = {
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, min.x, min.y, min.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, min.x, min.y, max.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, min.x, max.y, max.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, min.x, max.y, min.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, max.x, min.y, min.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, max.x, min.y, max.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, max.x, max.y, max.z).xy,
 | 
						|
							GetOffsetFromEntityInWorldCoords(entity, max.x, max.y, min.z).xy
 | 
						|
						}
 | 
						|
 | 
						|
						local centroid = vec2(0, 0)
 | 
						|
 | 
						|
						for i = 1, 8 do
 | 
						|
							centroid += points[i]
 | 
						|
						end
 | 
						|
 | 
						|
						centroid = centroid / 8
 | 
						|
						door.coords = vec3(centroid.x, centroid.y, door.coords.z)
 | 
						|
						door.entity = entity
 | 
						|
						Entity(entity).state.doorId = door.id
 | 
						|
					end
 | 
						|
				end
 | 
						|
 | 
						|
				if door.distance < 20 then
 | 
						|
					nearbyDoors[#nearbyDoors + 1] = door
 | 
						|
				end
 | 
						|
			elseif door.entity then
 | 
						|
				door.entity = nil
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		Wait(500)
 | 
						|
	end
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNetEvent('ox_doorlock:setState', function(id, state, source, data)
 | 
						|
	if not doors then return end
 | 
						|
 | 
						|
	if data then
 | 
						|
		doors[id] = data
 | 
						|
		createDoor(data)
 | 
						|
 | 
						|
		if NuiHasLoaded then
 | 
						|
			SendNuiMessage(json.encode({
 | 
						|
				action = 'updateDoorData',
 | 
						|
				data = data
 | 
						|
			}))
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	if Config.Notify and source == cache.serverId then
 | 
						|
		if state == 0 then
 | 
						|
			lib.notify({
 | 
						|
				type = 'success',
 | 
						|
				icon = 'unlock',
 | 
						|
				description = locale('unlocked_door')
 | 
						|
			})
 | 
						|
		else
 | 
						|
			lib.notify({
 | 
						|
				type = 'success',
 | 
						|
				icon = 'lock',
 | 
						|
				description = locale('locked_door')
 | 
						|
			})
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	local door = data or doors[id]
 | 
						|
	local double = door.doors
 | 
						|
	door.state = state
 | 
						|
 | 
						|
	if double then
 | 
						|
		DoorSystemSetDoorState(double[1].hash, door.state, false, false)
 | 
						|
		DoorSystemSetDoorState(double[2].hash, door.state, false, false)
 | 
						|
 | 
						|
		if door.holdOpen then
 | 
						|
			DoorSystemSetHoldOpen(double[1].hash, door.state == 0)
 | 
						|
			DoorSystemSetHoldOpen(double[2].hash, door.state == 0)
 | 
						|
		end
 | 
						|
 | 
						|
		while door.state == 1 and (not IsDoorClosed(double[1].hash) or not IsDoorClosed(double[2].hash)) do Wait(0) end
 | 
						|
	else
 | 
						|
		DoorSystemSetDoorState(door.hash, door.state, false, false)
 | 
						|
 | 
						|
		if door.holdOpen then DoorSystemSetHoldOpen(door.hash, door.state == 0) end
 | 
						|
		while door.state == 1 and not IsDoorClosed(door.hash) do Wait(0) end
 | 
						|
	end
 | 
						|
 | 
						|
	if door.state == state and door.distance and door.distance < 20 then
 | 
						|
		if Config.NativeAudio then
 | 
						|
			RequestScriptAudioBank('dlc_oxdoorlock/oxdoorlock', false)
 | 
						|
			local sound = state == 0 and door.unlockSound or door.lockSound or 'door_bolt'
 | 
						|
			local soundId = GetSoundId()
 | 
						|
 | 
						|
			PlaySoundFromCoord(soundId, sound, door.coords.x, door.coords.y, door.coords.z, 'DLC_OXDOORLOCK_SET', false, 0, false)
 | 
						|
			ReleaseSoundId(soundId)
 | 
						|
			ReleaseNamedScriptAudioBank('dlc_oxdoorlock/oxdoorlock')
 | 
						|
		else
 | 
						|
			local volume = (0.01 * GetProfileSetting(300)) / (door.distance / 2)
 | 
						|
			if volume > 1 then volume = 1 end
 | 
						|
			local sound = state == 0 and door.unlockSound or door.lockSound or 'door-bolt-4'
 | 
						|
 | 
						|
			SendNUIMessage({
 | 
						|
				action = 'playSound',
 | 
						|
				data = {
 | 
						|
					sound = sound,
 | 
						|
					volume = volume
 | 
						|
				}
 | 
						|
			})
 | 
						|
		end
 | 
						|
	end
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNetEvent('ox_doorlock:editDoorlock', function(id, data)
 | 
						|
	if source == '' then return end
 | 
						|
 | 
						|
	local door = doors[id]
 | 
						|
	local double = door.doors
 | 
						|
	local doorState = data and data.state or 0
 | 
						|
 | 
						|
	if data then
 | 
						|
		data.zone = door.zone or GetLabelText(GetNameOfZone(door.coords.x, door.coords.y, door.coords.z))
 | 
						|
 | 
						|
		-- hacky method to resolve a bug with "closest door" by forcing a distance recalculation
 | 
						|
		if door.distance < 20 then door.distance = 80 end
 | 
						|
	elseif ClosestDoor?.id == id then
 | 
						|
		ClosestDoor = nil
 | 
						|
	end
 | 
						|
 | 
						|
	if double then
 | 
						|
		for i = 1, 2 do
 | 
						|
			local doorHash = double[i].hash
 | 
						|
 | 
						|
			if data then
 | 
						|
				if data.doorRate or door.doorRate or not data.auto then
 | 
						|
					DoorSystemSetAutomaticRate(doorHash, data.doorRate or door.doorRate and 0.0 or 10.0, false, false)
 | 
						|
				end
 | 
						|
 | 
						|
				DoorSystemSetDoorState(doorHash, doorState, false, false)
 | 
						|
 | 
						|
				if data.holdOpen then DoorSystemSetHoldOpen(doorHash, doorState == 0) end
 | 
						|
			else
 | 
						|
				DoorSystemSetDoorState(doorHash, 4, false, false)
 | 
						|
				DoorSystemSetDoorState(doorHash, 0, false, false)
 | 
						|
 | 
						|
				if double[i].entity then
 | 
						|
					Entity(double[i].entity).state.doorId = nil
 | 
						|
				end
 | 
						|
			end
 | 
						|
		end
 | 
						|
	else
 | 
						|
		if data then
 | 
						|
			if data.doorRate or door.doorRate or not data.auto then
 | 
						|
				DoorSystemSetAutomaticRate(door.hash, data.doorRate or door.doorRate and 0.0 or 10.0, false, false)
 | 
						|
			end
 | 
						|
 | 
						|
			DoorSystemSetDoorState(door.hash, doorState, false, false)
 | 
						|
 | 
						|
			if data.holdOpen then DoorSystemSetHoldOpen(door.hash, doorState == 0) end
 | 
						|
		else
 | 
						|
			DoorSystemSetDoorState(door.hash, 4, false, false)
 | 
						|
			DoorSystemSetDoorState(door.hash, 0, false, false)
 | 
						|
 | 
						|
			if door.entity then
 | 
						|
				Entity(door.entity).state.doorId = nil
 | 
						|
			end
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	doors[id] = data
 | 
						|
 | 
						|
	if NuiHasLoaded then
 | 
						|
		SendNuiMessage(json.encode({
 | 
						|
			action = 'updateDoorData',
 | 
						|
			data = data or id
 | 
						|
		}))
 | 
						|
	end
 | 
						|
end)
 | 
						|
 | 
						|
ClosestDoor = nil
 | 
						|
 | 
						|
lib.callback.register('ox_doorlock:inputPassCode', function()
 | 
						|
	return ClosestDoor?.passcode and lib.inputDialog(locale('door_lock'), {
 | 
						|
		{
 | 
						|
			type = 'input',
 | 
						|
			label = locale('passcode'),
 | 
						|
			password = true,
 | 
						|
			icon = 'lock'
 | 
						|
		},
 | 
						|
	})?[1]
 | 
						|
end)
 | 
						|
 | 
						|
local lastTriggered = 0
 | 
						|
 | 
						|
local function useClosestDoor()
 | 
						|
	if not ClosestDoor then return false end
 | 
						|
 | 
						|
	local gameTimer = GetGameTimer()
 | 
						|
 | 
						|
	if gameTimer - lastTriggered > 500 then
 | 
						|
		lastTriggered = gameTimer
 | 
						|
		TriggerServerEvent('ox_doorlock:setState', ClosestDoor.id, ClosestDoor.state == 1 and 0 or 1)
 | 
						|
	end
 | 
						|
end
 | 
						|
 | 
						|
exports('useClosestDoor', useClosestDoor)
 | 
						|
 | 
						|
CreateThread(function()
 | 
						|
	local lockDoor = locale('lock_door')
 | 
						|
	local unlockDoor = locale('unlock_door')
 | 
						|
	local showUI
 | 
						|
	local drawSprite = Config.DrawSprite
 | 
						|
 | 
						|
	if drawSprite then
 | 
						|
		local sprite1 = drawSprite[0]?[1]
 | 
						|
		local sprite2 = drawSprite[1]?[1]
 | 
						|
 | 
						|
		if sprite1 then
 | 
						|
			RequestStreamedTextureDict(sprite1, true)
 | 
						|
		end
 | 
						|
 | 
						|
		if sprite2 then
 | 
						|
			RequestStreamedTextureDict(sprite2, true)
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	local SetDrawOrigin = SetDrawOrigin
 | 
						|
	local ClearDrawOrigin = ClearDrawOrigin
 | 
						|
	local DrawSprite = drawSprite and DrawSprite
 | 
						|
 | 
						|
	while true do
 | 
						|
		local num = #nearbyDoors
 | 
						|
 | 
						|
		if num > 0 then
 | 
						|
			local ratio = drawSprite and GetAspectRatio(true)
 | 
						|
			for i = 1, num do
 | 
						|
				local door = nearbyDoors[i]
 | 
						|
 | 
						|
				if door.distance < door.maxDistance then
 | 
						|
					if door.distance < (ClosestDoor?.distance or 10) then
 | 
						|
						ClosestDoor = door
 | 
						|
					end
 | 
						|
 | 
						|
					if drawSprite and not door.hideUi then
 | 
						|
						local sprite = drawSprite[door.state]
 | 
						|
 | 
						|
						if sprite then
 | 
						|
							SetDrawOrigin(door.coords.x, door.coords.y, door.coords.z)
 | 
						|
							DrawSprite(sprite[1], sprite[2], sprite[3], sprite[4], sprite[5], sprite[6] * ratio, sprite[7], sprite[8], sprite[9], sprite[10], sprite[11])
 | 
						|
							ClearDrawOrigin()
 | 
						|
						end
 | 
						|
					end
 | 
						|
				end
 | 
						|
			end
 | 
						|
		else ClosestDoor = nil end
 | 
						|
 | 
						|
		if ClosestDoor and ClosestDoor.distance < ClosestDoor.maxDistance then
 | 
						|
			if Config.DrawTextUI and not ClosestDoor.hideUi and ClosestDoor.state ~= showUI then
 | 
						|
				lib.showTextUI(ClosestDoor.state == 0 and lockDoor or unlockDoor)
 | 
						|
				showUI = ClosestDoor.state
 | 
						|
			end
 | 
						|
 | 
						|
			if not PickingLock and IsDisabledControlJustReleased(0, 38) then
 | 
						|
				useClosestDoor()
 | 
						|
			end
 | 
						|
		elseif showUI then
 | 
						|
			lib.hideTextUI()
 | 
						|
			showUI = nil
 | 
						|
		end
 | 
						|
 | 
						|
		Wait(num > 0 and 0 or 500)
 | 
						|
	end
 | 
						|
end)
 |