279 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			279 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
 | 
						|
-- localise frequently used Lua globals
 | 
						|
local os_time, os_difftime, os_date, math_floor = os.time, os.difftime, os.date, math.floor
 | 
						|
 | 
						|
-- localise frequently used natives
 | 
						|
local DoesEntityExist, GetPlayerRoutingBucket, GetEntityCoords, DeleteEntity, GetVehicleEngineHealth, GetEntityRoutingBucket = 
 | 
						|
DoesEntityExist, GetPlayerRoutingBucket, GetEntityCoords, DeleteEntity, GetVehicleEngineHealth, GetEntityRoutingBucket
 | 
						|
 | 
						|
-- task system
 | 
						|
local tasks = {}
 | 
						|
 | 
						|
local function GetTime()
 | 
						|
	local time = os_time()
 | 
						|
 | 
						|
	return {
 | 
						|
		day		= tonumber(os_date("%w", time)),
 | 
						|
		hour	= tonumber(os_date("%H", time)),
 | 
						|
		minute	= tonumber(os_date("%M", time))
 | 
						|
	}
 | 
						|
end
 | 
						|
 | 
						|
local taskRunning = false
 | 
						|
local function StartTaskThread()
 | 
						|
	if (taskRunning) then return end
 | 
						|
 | 
						|
	taskRunning = true
 | 
						|
 | 
						|
	local lastTime = GetTime()
 | 
						|
 | 
						|
	while (taskRunning) do
 | 
						|
		Wait(1000)
 | 
						|
 | 
						|
		local time = GetTime()
 | 
						|
 | 
						|
		if (time.minute ~= lastTime.minute or time.hour ~= lastTime.hour or time.day ~= lastTime.day) then
 | 
						|
			for i = 1, #tasks do
 | 
						|
				if ((not tasks[i].day or tasks[i].day == time.day) and tasks[i].hour == time.hour and tasks[i].minute == time.minute) then
 | 
						|
					tasks[i].Run()
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			lastTime = time
 | 
						|
		end
 | 
						|
	end
 | 
						|
end
 | 
						|
 | 
						|
local function AddTask(task, d, h, m)
 | 
						|
	assert(task and type(task) == "function", "Parameter \"task\" must be a function!")
 | 
						|
	assert(not d or type(d) == "number", "Parameter \"day\" must be a number!")
 | 
						|
	assert(h and type(h) == "number", "Parameter \"hour\" must be a number!")
 | 
						|
	assert(m and type(m) == "number", "Parameter \"minute\" must be a number!")
 | 
						|
 | 
						|
	tasks[#tasks + 1] = {
 | 
						|
		day		= d and math_floor(d),
 | 
						|
		hour	= math_floor(h),
 | 
						|
		minute	= math_floor(m),
 | 
						|
		Run		= task
 | 
						|
	}
 | 
						|
 | 
						|
	if (not taskRunning) then
 | 
						|
		CreateThread(StartTaskThread)
 | 
						|
	end
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
 | 
						|
-- get all players sorted by bucket
 | 
						|
local function GetPositionsOfAllPlayersByBucket()
 | 
						|
	local playerPositions = {}
 | 
						|
 | 
						|
	local players = GetPlayers()
 | 
						|
	for i = 1, #players do
 | 
						|
		local ped = GetPlayerPed(players[i])
 | 
						|
		if (DoesEntityExist(ped)) then
 | 
						|
			local bucket = GetPlayerRoutingBucket(players[i])
 | 
						|
			if (not playerPositions[bucket]) then
 | 
						|
				playerPositions[bucket] = {}
 | 
						|
			end
 | 
						|
 | 
						|
			playerPositions[bucket][#playerPositions[bucket] + 1] = GetEntityCoords(ped)
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	return playerPositions
 | 
						|
end
 | 
						|
 | 
						|
-- get closest position and distance from list
 | 
						|
local function GetClosestDistanceFromList(position, positionList)
 | 
						|
	local closestDistance = 100000
 | 
						|
 | 
						|
	for i = 1, positionList and #positionList or 0 do
 | 
						|
		local tempDist = #(position - positionList[i])
 | 
						|
		if (tempDist < closestDistance) then
 | 
						|
			closestDistance = tempDist
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	return closestDistance
 | 
						|
end
 | 
						|
 | 
						|
-- runs the whole cleanup process once
 | 
						|
function CleanupProcess()
 | 
						|
	local timeDiff = 0
 | 
						|
	if (Cleanup.timeThreshold) then
 | 
						|
		local currentTime = os_time()
 | 
						|
		local threshold = math_floor(3600 * Cleanup.timeThreshold)
 | 
						|
		timeDiff = os_difftime(currentTime, threshold)
 | 
						|
	end
 | 
						|
 | 
						|
	local playerPositions = GetPositionsOfAllPlayersByBucket()
 | 
						|
 | 
						|
	local toDelete = {}
 | 
						|
 | 
						|
	for id, vehicleData in pairs(savedVehicles) do
 | 
						|
		local position = DoesEntityExist(vehicleData.handle) and GetEntityCoords(vehicleData.handle) or vehicleData.position
 | 
						|
 | 
						|
		for i = 1, #Cleanup.ignoredZones do
 | 
						|
			if (#(position - Cleanup.ignoredZones[i].position) < Cleanup.ignoredZones[i].radius) then
 | 
						|
				goto cleanupDone -- continue
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		for i = 1, #Cleanup.ignoredPlates do
 | 
						|
			if (vehicleData.tuning[1]:find(Cleanup.ignoredPlates[i]:upper())) then
 | 
						|
				goto cleanupDone -- continue
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		for i = 1, #Cleanup.ignoredModels do
 | 
						|
			if (vehicleData.model == Cleanup.ignoredModels[i]) then
 | 
						|
				goto cleanupDone -- continue
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		if (Cleanup.timeThreshold and vehicleData.lastUpdate < timeDiff) then
 | 
						|
			toDelete[#toDelete + 1] = id
 | 
						|
			TriggerEvent("AP:cleanup:deletingVehicle", vehicleData.handle, vehicleData.tuning[1], "time")
 | 
						|
			goto cleanupDone -- continue
 | 
						|
		end
 | 
						|
 | 
						|
		if (Cleanup.engineThreshold and vehicleData.status[3] <= Cleanup.engineThreshold) then
 | 
						|
			toDelete[#toDelete + 1] = id
 | 
						|
			TriggerEvent("AP:cleanup:deletingVehicle", vehicleData.handle, vehicleData.tuning[1], "engineHealth")
 | 
						|
			goto cleanupDone -- continue
 | 
						|
		end
 | 
						|
 | 
						|
		if (Cleanup.distanceThreshold) then
 | 
						|
			local distance = GetClosestDistanceFromList(position, playerPositions[vehicleData.bucket])
 | 
						|
			if (distance > Cleanup.distanceThreshold) then
 | 
						|
				toDelete[#toDelete + 1] = id
 | 
						|
				TriggerEvent("AP:cleanup:deletingVehicle", vehicleData.handle, vehicleData.tuning[1], "distance")
 | 
						|
				goto cleanupDone -- continue
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		for i = 1, #Cleanup.zones do
 | 
						|
			if (#(position - Cleanup.zones[i].position) < Cleanup.zones[i].radius) then
 | 
						|
				toDelete[#toDelete + 1] = id
 | 
						|
				TriggerEvent("AP:cleanup:deletingVehicle", vehicleData.handle, vehicleData.tuning[1], "zone_" .. i)
 | 
						|
				goto cleanupDone -- continue
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		::cleanupDone::
 | 
						|
	end
 | 
						|
 | 
						|
	for i, id in ipairs(toDelete) do
 | 
						|
		if (savedVehicles[id].handle and DoesEntityExist(savedVehicles[id].handle)) then
 | 
						|
			DeleteEntity(savedVehicles[id].handle)
 | 
						|
 | 
						|
			LogDebug("Cleanup removed \"%s\" (\"%s\").", id, savedVehicles[id].tuning[1])
 | 
						|
		end
 | 
						|
 | 
						|
		if (Cleanup.storeVehicles) then
 | 
						|
			StoreVehicle(savedVehicles[id].tuning[1], savedVehicles[id].handle)
 | 
						|
		end
 | 
						|
 | 
						|
		savedVehicles[id] = nil
 | 
						|
		spawnQueue[id] = nil
 | 
						|
	end
 | 
						|
 | 
						|
	DeleteVehiclesFromDB(toDelete)
 | 
						|
 | 
						|
	local othersCount = 0
 | 
						|
	if (Cleanup.allVehicles) then
 | 
						|
		local vehicles = GetAllVehicles()
 | 
						|
		for i = 1, #vehicles do
 | 
						|
			if (not DoesEntityExist(vehicles[i])) then
 | 
						|
				goto cleanupOthersDone -- continue
 | 
						|
			end
 | 
						|
 | 
						|
			local position = GetEntityCoords(vehicles[i])
 | 
						|
 | 
						|
			for i = 1, #Cleanup.ignoredZones do
 | 
						|
				if (#(position - Cleanup.ignoredZones[i].position) < Cleanup.ignoredZones[i].radius) then
 | 
						|
					goto cleanupOthersDone -- continue
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			if (#Cleanup.ignoredPlates > 0) then
 | 
						|
				local plate = GetVehicleNumberPlateText(vehicles[i])
 | 
						|
				for i = 1, #Cleanup.ignoredPlates do
 | 
						|
					if (plate:find(Cleanup.ignoredPlates[i]:upper())) then
 | 
						|
						goto cleanupOthersDone -- continue
 | 
						|
					end
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			if (#Cleanup.ignoredModels > 0) then
 | 
						|
				local model = GetEntityModel(vehicles[i])
 | 
						|
				for i = 1, #Cleanup.ignoredModels do
 | 
						|
					if (model == Cleanup.ignoredModels[i]) then
 | 
						|
						goto cleanupOthersDone -- continue
 | 
						|
					end
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			if (Cleanup.engineThreshold and GetVehicleEngineHealth(vehicles[i]) <= Cleanup.engineThreshold) then
 | 
						|
				DeleteEntity(vehicles[i])
 | 
						|
				othersCount += 1
 | 
						|
				goto cleanupOthersDone -- continue
 | 
						|
			end
 | 
						|
 | 
						|
			if (Cleanup.distanceThreshold) then
 | 
						|
				local distance = GetClosestDistanceFromList(position, playerPositions[GetEntityRoutingBucket(vehicles[i])])
 | 
						|
				if (distance > Cleanup.distanceThreshold) then
 | 
						|
					DeleteEntity(vehicles[i])
 | 
						|
					othersCount += 1
 | 
						|
					goto cleanupOthersDone -- continue
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			for i = 1, #Cleanup.zones do
 | 
						|
				if (#(position - Cleanup.zones[i].position) < Cleanup.zones[i].radius) then
 | 
						|
					DeleteEntity(vehicles[i])
 | 
						|
					othersCount += 1
 | 
						|
					goto cleanupOthersDone -- continue
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			::cleanupOthersDone::
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	TriggerClientEvent("AP:showNotification", -1, Cleanup.deleteNotification)
 | 
						|
 | 
						|
	Log("Cleanup complete. Removed %s saved vehicles. Removed %s other vehicles.", #toDelete, othersCount)
 | 
						|
end
 | 
						|
 | 
						|
-- add timed clean up tasks
 | 
						|
for i = 1, #Cleanup.times do
 | 
						|
	local day = Cleanup.times[i].day
 | 
						|
	local hour = Cleanup.times[i].hour
 | 
						|
	local minute = Cleanup.times[i].minute
 | 
						|
	AddTask(CleanupProcess, day, hour, minute)
 | 
						|
 | 
						|
	for j = 1, #Cleanup.notificationTimes do
 | 
						|
		local d = day
 | 
						|
		local h = hour
 | 
						|
		local m = minute - Cleanup.notificationTimes[j]
 | 
						|
		if (m < 0) then
 | 
						|
			m += 60
 | 
						|
			h -= 1
 | 
						|
			if (h < 0) then
 | 
						|
				h += 24
 | 
						|
				if (d) then
 | 
						|
					d -= 1
 | 
						|
					if (d < 0) then
 | 
						|
						d += 7
 | 
						|
					end
 | 
						|
				end
 | 
						|
			end
 | 
						|
		end
 | 
						|
 | 
						|
		AddTask(function()
 | 
						|
			TriggerClientEvent("AP:showNotification", -1, Cleanup.timeLeftNotification:format(Cleanup.notificationTimes[j]))
 | 
						|
		end, d, h, m)
 | 
						|
	end
 | 
						|
end
 |