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)
 | 
