Main/resources/[jobs]/[police]/lvc/UTIL/cl_storage.lua
2025-06-07 08:51:21 +02:00

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)