415 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			415 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| --[[
 | |
| ---------------------------------------------------
 | |
| LUXART VEHICLE CONTROL V3 (FOR FIVEM)
 | |
| ---------------------------------------------------
 | |
| Coded by Lt.Caine
 | |
| ELS Clicks by Faction
 | |
| Additional Modification by TrevorBarns
 | |
| ---------------------------------------------------
 | |
| FILE: cl_storage.lua
 | |
| PURPOSE: Handle save/load functions and version 
 | |
| 		 checking
 | |
| ---------------------------------------------------
 | |
| This program is free software: you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation, either version 3 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| This program is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | |
| ---------------------------------------------------
 | |
| ]]
 | |
| STORAGE = { }
 | |
| 
 | |
| local save_prefix = 'lvc_'..community_id..'_'
 | |
| local repo_version = nil
 | |
| local backup_tone_table = {}
 | |
| local custom_tone_names = false
 | |
| local SIRENS_backup_string = nil
 | |
| local profiles = { }
 | |
| 
 | |
| --	forward local fn declaration
 | |
| local IsNewerVersion
 | |
|  
 | |
| ------------------------------------------------
 | |
| --Deletes all saved KVPs for that vehicle profile
 | |
| --	This should never be removed. It is the only easy way for end users to delete LVC data.
 | |
| RegisterCommand('lvcfactoryreset', function(source, args)
 | |
| 	local choice = HUD:FrontEndAlert(Lang:t('warning.warning'), Lang:t('warning.factory_reset'), Lang:t('warning.facory_reset_options'))
 | |
| 	if choice then
 | |
| 		STORAGE:FactoryReset()
 | |
| 	end
 | |
| end)
 | |
| 
 | |
| function STORAGE:FactoryReset()
 | |
| 	STORAGE:DeleteKVPs(save_prefix)
 | |
| 	STORAGE:ResetSettings()
 | |
| 	UTIL:Print(Lang:t('info.factory_reset_success_console'), true)
 | |
| 	HUD:ShowNotification(Lang:t('info.factory_reset_success_frontend'), true)
 | |
| end
 | |
| 
 | |
| --Prints all KVP keys and values to console
 | |
| --if GetResourceMetadata(GetCurrentResourceName(), 'debug_mode', 0) == 'true' then
 | |
| 	RegisterCommand('lvcdumpkvp', function(source, args)
 | |
| 		UTIL:Print('^4LVC ^5STORAGE: ^7Dumping KVPs...')
 | |
| 		local handle = StartFindKvp(save_prefix);
 | |
| 		local key = FindKvp(handle)
 | |
| 		while key ~= nil do
 | |
| 			if GetResourceKvpString(key) ~= nil then
 | |
| 				UTIL:Print('^4LVC ^5STORAGE Found: ^7"'..key..'" "'..GetResourceKvpString(key)..'", STRING', true)
 | |
| 			elseif GetResourceKvpInt(key) ~= nil then
 | |
| 				UTIL:Print('^4LVC ^5STORAGE Found: ^7"'..key..'" "'..GetResourceKvpInt(key)..'", INT', true)
 | |
| 			elseif GetResourceKvpFloat(key) ~= nil then
 | |
| 				UTIL:Print('^4LVC ^5STORAGE Found: ^7"'..key..'" "'..GetResourceKvpFloat(key)..'", FLOAT', true)
 | |
| 			end
 | |
| 			key = FindKvp(handle)
 | |
| 			Wait(0)
 | |
| 		end
 | |
| 		UTIL:Print('^4LVC ^5STORAGE: ^7Finished Dumping KVPs...')
 | |
| 	end)
 | |
| --end
 | |
| ------------------------------------------------
 | |
| -- Resource Start Initialization
 | |
| CreateThread(function()
 | |
| 	TriggerServerEvent('lvc:GetRepoVersion_s')
 | |
| 	STORAGE:FindSavedProfiles()
 | |
| end)
 | |
| 
 | |
| --[[Function for Deleting KVPs]]
 | |
| function STORAGE:DeleteKVPs(prefix)
 | |
| 	local handle = StartFindKvp(prefix);
 | |
| 	local key = FindKvp(handle)
 | |
| 	while key ~= nil do
 | |
| 		DeleteResourceKvp(key)
 | |
| 		UTIL:Print('^3LVC Info: Deleting Key \'' .. key .. '\'', true)
 | |
| 		key = FindKvp(handle)
 | |
| 		Wait(0)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| --[[Getter for current version used in RageUI.]]
 | |
| function STORAGE:GetCurrentVersion()
 | |
| 	local curr_version = GetResourceMetadata(GetCurrentResourceName(), 'version', 0)
 | |
| 	if curr_version ~= nil then
 | |
| 		return curr_version
 | |
| 	else
 | |
| 		return 'unknown'
 | |
| 	end
 | |
| end
 | |
| 
 | |
| --[[Getter for repo version used in RageUI.]]
 | |
| function STORAGE:GetRepoVersion()
 | |
| 	return repo_version
 | |
| end
 | |
| 
 | |
| --[[Getter for out-of-date notification for RageUI.]]
 | |
| function STORAGE:GetIsNewerVersion()
 | |
| 	return IsNewerVersion(repo_version, STORAGE:GetCurrentVersion())
 | |
| end
 | |
| 
 | |
| --[[Saves HUD settings, separated from SaveSettings]]
 | |
| function STORAGE:SaveHUDSettings()
 | |
| 	local hud_save_data = { Show_HUD = HUD:GetHudState(),
 | |
| 							HUD_Scale = HUD:GetHudScale(), 
 | |
| 							HUD_pos = HUD:GetHudPosition(),
 | |
| 							HUD_backlight_mode = HUD:GetHudBacklightMode(),
 | |
| 						  }
 | |
| 	SetResourceKvp(save_prefix .. 'hud_data',  json.encode(hud_save_data))
 | |
| end
 | |
| 
 | |
| 
 | |
| --[[Saves all KVP values.]]
 | |
| function STORAGE:SaveSettings()
 | |
| 	UTIL:Print('^4LVC: ^5STORAGE: ^7Saving Settings...')
 | |
| 	SetResourceKvp(save_prefix..'save_version', STORAGE:GetCurrentVersion())
 | |
| 
 | |
| 	--HUD Settings
 | |
| 	STORAGE:SaveHUDSettings()
 | |
| 	
 | |
| 	--Tone Names
 | |
| 	if custom_tone_names then
 | |
| 		local tone_names = { }
 | |
| 		for i, siren_pkg in pairs(SIRENS) do
 | |
| 			table.insert(tone_names, siren_pkg.Name)
 | |
| 		end
 | |
| 		SetResourceKvp(save_prefix .. 'tone_names', json.encode(tone_names))
 | |
| 		UTIL:Print('^4LVC ^5STORAGE: ^7saving '..save_prefix..'tone_names...')		
 | |
| 	end
 | |
| 	
 | |
| 	--Profile Specific Settings
 | |
| 	if UTIL:GetVehicleProfileName() ~= nil then
 | |
| 		local profile_name = string.gsub(UTIL:GetVehicleProfileName(), ' ', '_')
 | |
| 		if profile_name ~= nil then
 | |
| 			local tone_options_encoded = json.encode(UTIL:GetToneOptionsTable())
 | |
| 			local profile_save_data = {  PMANU 				= UTIL:GetToneID('PMANU'), 
 | |
| 										 SMANU 				= UTIL:GetToneID('SMANU'),
 | |
| 										 AUX   				= UTIL:GetToneID('AUX'),
 | |
| 										 airhorn_intrp 		= tone_airhorn_intrp,
 | |
| 										 main_reset_standby = tone_main_reset_standby,
 | |
| 										 park_kill 			= park_kill,
 | |
| 										 tone_options 		= tone_options_encoded,															  
 | |
| 									   }
 | |
| 							
 | |
| 			SetResourceKvp(save_prefix .. 'profile_'..profile_name..'!',  json.encode(profile_save_data))
 | |
| 			UTIL:Print('^4LVC ^5STORAGE: ^7saving '..save_prefix .. 'profile_'..profile_name..'!')
 | |
| 
 | |
| 			--Audio Settings
 | |
| 			local audio_save_data = {	
 | |
| 										radio_masterswitch			= AUDIO.radio_masterswitch,				
 | |
| 										button_sfx_scheme 			= AUDIO.button_sfx_scheme,
 | |
| 										on_volume 					= AUDIO.on_volume,
 | |
| 										off_volume 					= AUDIO.off_volume,
 | |
| 										upgrade_volume 				= AUDIO.upgrade_volume,
 | |
| 										downgrade_volume 			= AUDIO.downgrade_volume,
 | |
| 										activity_reminder_volume 	= AUDIO.activity_reminder_volume,
 | |
| 										hazards_volume 				= AUDIO.hazards_volume,
 | |
| 										lock_volume 				= AUDIO.lock_volume,
 | |
| 										lock_reminder_volume 		= AUDIO.lock_reminder_volume,
 | |
| 										airhorn_button_SFX 			= AUDIO.airhorn_button_SFX,
 | |
| 										manu_button_SFX 			= AUDIO.manu_button_SFX,
 | |
| 										activity_reminder_index 	= AUDIO:GetActivityReminderIndex(),	
 | |
| 									}						
 | |
| 			SetResourceKvp(save_prefix..'profile_'..profile_name..'_audio_data',  json.encode(audio_save_data))
 | |
| 			UTIL:Print('^4LVC ^5STORAGE: ^7saving profile_'..profile_name..'_audio_data')
 | |
| 		else
 | |
| 			HUD:ShowNotification('~b~LVC: ~r~SAVE ERROR~s~: profile_name after gsub is nil.', true)
 | |
| 		end
 | |
| 	else
 | |
| 		HUD:ShowNotification('~b~LVC: ~r~SAVE ERROR~s~: UTIL:GetVehicleProfileName() returned nil.', true)
 | |
| 	end
 | |
| 	UTIL:Print('^4LVC ^5STORAGE: ^7Finished Saving Settings...')
 | |
| end
 | |
| 
 | |
| ------------------------------------------------
 | |
| --[[Loads all KVP values.]]
 | |
| function STORAGE:LoadSettings(profile_name)	
 | |
| 	UTIL:Print('^4LVC ^5STORAGE: ^7Loading Settings...')
 | |
| 	local comp_version = GetResourceMetadata(GetCurrentResourceName(), 'compatible', 0)
 | |
| 	local save_version = GetResourceKvpString(save_prefix .. 'save_version')
 | |
| 	local incompatible = IsNewerVersion(comp_version, save_version) == 'older'
 | |
| 
 | |
| 	--Is save present if so what version
 | |
| 	if incompatible then
 | |
| 		AddTextEntry('lvc_mismatch_version','~y~~h~Warning:~h~ ~s~Luxart Vehicle Control Save Version Mismatch.\n~b~Compatible Version: ' .. comp_version .. '\n~o~Save Version: ' .. save_version .. '~s~\nYou may experience issues, to prevent this message from appearing verify settings and resave.')
 | |
| 		SetNotificationTextEntry('lvc_mismatch_version')
 | |
| 		DrawNotification(false, true)
 | |
| 	end
 | |
| 	
 | |
| 	local hud_save_data = GetResourceKvpString(save_prefix..'hud_data')
 | |
| 	if hud_save_data ~= nil then
 | |
| 		hud_save_data = json.decode(hud_save_data)
 | |
| 		HUD:SetHudState(hud_save_data.Show_HUD)
 | |
| 		HUD:SetHudScale(hud_save_data.HUD_Scale)
 | |
| 		HUD:SetHudPosition(hud_save_data.HUD_pos)
 | |
| 		HUD:SetHudBacklightMode(hud_save_data.HUD_backlight_mode)
 | |
| 		UTIL:Print('^4LVC ^5STORAGE: ^7loaded HUD data.')		
 | |
| 	end
 | |
| 	
 | |
| 	if save_version ~= nil then
 | |
| 		--Tone Names
 | |
| 		if main_siren_settings_masterswitch then
 | |
| 			local tone_names = GetResourceKvpString(save_prefix..'tone_names')
 | |
| 			if tone_names ~= nil then
 | |
| 				tone_names = json.decode(tone_names)
 | |
| 				for i, name in pairs(tone_names) do
 | |
| 					if SIRENS[i] ~= nil then
 | |
| 						SIRENS[i].Name = name
 | |
| 					end
 | |
| 				end
 | |
| 			end
 | |
| 			UTIL:Print('^4LVC ^5STORAGE: ^7loaded custom tone names.')
 | |
| 		end
 | |
| 		
 | |
| 		--Profile Specific Settings
 | |
| 		if UTIL:GetVehicleProfileName() ~= false then
 | |
| 			local profile_name = profile_name or string.gsub(UTIL:GetVehicleProfileName(), ' ', '_')	
 | |
| 			if profile_name ~= nil then
 | |
| 				local profile_save_data = GetResourceKvpString(save_prefix..'profile_'..profile_name..'!')
 | |
| 				if profile_save_data ~= nil then
 | |
| 					profile_save_data = json.decode(profile_save_data)
 | |
| 					UTIL:SetToneByID('PMANU', profile_save_data.PMANU)
 | |
| 					UTIL:SetToneByID('SMANU', profile_save_data.SMANU)
 | |
| 					UTIL:SetToneByID('AUX', profile_save_data.AUX)
 | |
| 					if main_siren_settings_masterswitch then
 | |
| 						tone_airhorn_intrp 		= profile_save_data.airhorn_intrp
 | |
| 						tone_main_reset_standby = profile_save_data.main_reset_standby
 | |
| 						park_kill 				= profile_save_data.park_kill
 | |
| 						local tone_options = json.decode(profile_save_data.tone_options)
 | |
| 							if tone_options ~= nil then
 | |
| 								for tone_id, option in pairs(tone_options) do
 | |
| 									tone_id = tonumber(tone_id)
 | |
| 									option = tonumber(option)
 | |
| 									if SIRENS[tone_id] ~= nil then
 | |
| 										UTIL:SetToneOption(tone_id, option)
 | |
| 									end
 | |
| 								end
 | |
| 							end
 | |
| 					end
 | |
| 					UTIL:Print('^4LVC ^5STORAGE: ^7loaded '..profile_name..'.')
 | |
| 				end
 | |
| 				--Audio Settings 
 | |
| 				local audio_save_data = GetResourceKvpString(save_prefix..'profile_'..profile_name..'_audio_data')
 | |
| 				if audio_save_data ~= nil then
 | |
| 					audio_save_data = json.decode(audio_save_data)
 | |
| 					if audio_save_data.radio_masterswitch ~= nil then
 | |
| 						AUDIO.radio_masterswitch			= audio_save_data.radio_masterswitch
 | |
| 					end
 | |
| 					AUDIO.button_sfx_scheme 		= audio_save_data.button_sfx_scheme
 | |
| 					AUDIO.on_volume 				= audio_save_data.on_volume
 | |
| 					AUDIO.off_volume 				= audio_save_data.off_volume
 | |
| 					AUDIO.upgrade_volume 			= audio_save_data.upgrade_volume
 | |
| 					AUDIO.downgrade_volume 			= audio_save_data.downgrade_volume
 | |
| 					AUDIO.activity_reminder_volume 	= audio_save_data.activity_reminder_volume
 | |
| 					AUDIO.hazards_volume 			= audio_save_data.hazards_volume
 | |
| 					AUDIO.lock_volume 				= audio_save_data.lock_volume
 | |
| 					AUDIO.lock_reminder_volume 		= audio_save_data.lock_reminder_volume
 | |
| 					AUDIO.airhorn_button_SFX 		= audio_save_data.airhorn_button_SFX
 | |
| 					AUDIO.manu_button_SFX 			= audio_save_data.manu_button_SFX
 | |
| 					AUDIO:SetActivityReminderIndex(audio_save_data.activity_reminder_index)
 | |
| 					UTIL:Print('^4LVC ^5STORAGE: ^7loaded audio data.')
 | |
| 				end
 | |
| 			else
 | |
| 				HUD:ShowNotification('~b~LVC:~r~ LOADING ERROR~s~: profile_name after gsub is nil.', true)
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 	UTIL:Print('^4LVC ^5STORAGE: ^7Finished Loading Settings...')
 | |
| end
 | |
| 
 | |
| ------------------------------------------------
 | |
| --[[Resets all KVP/menu values to their default.]]
 | |
| function STORAGE:ResetSettings()
 | |
| 	UTIL:Print('^4LVC ^5STORAGE: ^7Resetting Settings...')
 | |
| 
 | |
| 	--Storage State
 | |
| 	custom_tone_names 		= false
 | |
| 	profiles = { }
 | |
| 	STORAGE:FindSavedProfiles()
 | |
| 
 | |
| 	--LVC State
 | |
| 	key_lock 				= false				
 | |
| 	tone_main_reset_standby = reset_to_standby_default
 | |
| 	tone_airhorn_intrp 		= airhorn_interrupt_default
 | |
| 	park_kill 				= park_kill_default
 | |
| 
 | |
| 	--HUD State
 | |
| 	HUD:SetHudState(hud_first_default)
 | |
| 	HUD:SetHudScale(0.7)
 | |
| 	HUD:ResetPosition()
 | |
| 	HUD:SetHudBacklightMode(1)
 | |
| 	
 | |
| 	--Extra Tone Resets
 | |
| 	UTIL:SetToneByPos('ARHRN', 1)
 | |
| 	UTIL:SetToneByPos('PMANU', 2)
 | |
| 	UTIL:SetToneByPos('SMANU', 3)
 | |
| 	UTIL:SetToneByPos('AUX', 2)
 | |
| 	UTIL:SetToneByPos('MAIN_MEM', 2)
 | |
| 
 | |
| 	STORAGE:RestoreBackupTable()
 | |
| 	UTIL:BuildToneOptions()
 | |
| 	
 | |
| 	--Audio Settings
 | |
| 	AUDIO.radio_masterswitch 		= true
 | |
| 	AUDIO.airhorn_button_SFX 		= false
 | |
| 	AUDIO.manu_button_SFX 			= false
 | |
| 	AUDIO:SetActivityReminderIndex(1)
 | |
| 
 | |
| 	AUDIO.button_sfx_scheme 		= default_sfx_scheme_name
 | |
| 	AUDIO.on_volume 				= default_on_volume	
 | |
| 	AUDIO.off_volume 				= default_off_volume	
 | |
| 	AUDIO.upgrade_volume 			= default_upgrade_volume	
 | |
| 	AUDIO.downgrade_volume 			= default_downgrade_volume
 | |
| 	AUDIO.hazards_volume 			= default_hazards_volume
 | |
| 	AUDIO.lock_volume 				= default_lock_volume
 | |
| 	AUDIO.lock_reminder_volume 		= default_lock_reminder_volume
 | |
| 	AUDIO.activity_reminder_volume 	= default_reminder_volume
 | |
| 	UTIL:Print('^4LVC ^5STORAGE: ^7Finished Resetting Settings...')
 | |
| end
 | |
| 
 | |
| ------------------------------------------------
 | |
| --[[Find all profile names of all saved KVP.]]
 | |
| function STORAGE:FindSavedProfiles()
 | |
| 	local handle = StartFindKvp(save_prefix..'profile_');
 | |
| 	local key = FindKvp(handle)
 | |
| 	while key ~= nil do
 | |
| 		if string.match(key, '(.*)!$') then
 | |
| 			local saved_profile_name = string.match(key, save_prefix..'profile_(.*)!$')
 | |
| 			
 | |
| 			--Duplicate checking
 | |
| 			local found = false
 | |
| 			for _, profile_name in ipairs(profiles) do
 | |
| 				if profile_name == saved_profile_name then
 | |
| 					found = true
 | |
| 				end
 | |
| 			end
 | |
| 			
 | |
| 			if not found then
 | |
| 				table.insert(profiles, saved_profile_name)
 | |
| 			end
 | |
| 		end
 | |
| 		key = FindKvp(handle)
 | |
| 		Wait(0)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| function STORAGE:GetSavedProfiles()
 | |
| 	local cur_profile = UTIL:GetVehicleProfileName()
 | |
| 	for i, profile in ipairs(profiles) do
 | |
| 		if profile == cur_profile then
 | |
| 			table.remove(profiles, i)
 | |
| 		end
 | |
| 	end
 | |
| 	
 | |
| 	return profiles
 | |
| end
 | |
| ------------------------------------------------
 | |
| --[[Setter for JSON string backup of SIRENS table in case of reset since we modify SIREN table directly.]]
 | |
| function STORAGE:SetBackupTable()
 | |
| 	SIRENS_backup_string = json.encode(SIRENS)
 | |
| end
 | |
| 
 | |
| --[[Setter for SIRENS table using backup string of table.]]
 | |
| function STORAGE:RestoreBackupTable()
 | |
| 	SIRENS = json.decode(SIRENS_backup_string)
 | |
| end
 | |
| 
 | |
| --[[Setter for bool that is used in saving to determine if tone strings have been modified.]]
 | |
| function STORAGE:SetCustomToneStrings(toggle)
 | |
| 	custom_tone_names = toggle
 | |
| end
 | |
| 
 | |
| ------------------------------------------------
 | |
| --HELPER FUNCTIONS for main siren settings saving:end
 | |
| --Compare Version Strings: Is version newer than test_version
 | |
| IsNewerVersion = function(version, test_version)
 | |
| 	if version == nil or test_version == nil then
 | |
| 		return 'unknown'
 | |
| 	end
 | |
| 
 | |
| 	if type(version) == 'string' then
 | |
| 		version = semver(version)
 | |
| 	end
 | |
| 	if type(test_version) == 'string' then
 | |
| 		test_version = semver(test_version)
 | |
| 	end
 | |
| 
 | |
| 	if version > test_version then
 | |
| 		return 'older'
 | |
| 	elseif version < test_version then
 | |
| 		return 'newer'
 | |
| 	elseif version == test_version then
 | |
| 		return 'equal'
 | |
| 	end
 | |
| end
 | |
| 
 | |
| ---------------------------------------------------------------------
 | |
| --[[Callback for Server -> Client version update.]]
 | |
| RegisterNetEvent('lvc:SendRepoVersion_c')
 | |
| AddEventHandler('lvc:SendRepoVersion_c', function(version)
 | |
| 	repo_version = version
 | |
| end) | 
