From 957960588bb104ba533884e79f765e4392e09cb9 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 21 Jan 2020 20:50:30 +0000 Subject: [PATCH] UI settings now get saved and loaded --- __resource.lua | 3 +- cl_radar.lua | 26 +++++++++- nui/radar.css | 8 ++- nui/radar.js | 101 +++++++++++++++++++++++++++++++++++--- sv_saving.lua | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 sv_saving.lua diff --git a/__resource.lua b/__resource.lua index 5e2948a..2bad2b2 100644 --- a/__resource.lua +++ b/__resource.lua @@ -10,7 +10,7 @@ resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937' name 'Wraith ARS 2X' description 'An advanced radar system for FiveM' author 'WolfKnight' -version 'beta3' +version 'beta3b' files { "nui/radar.html", @@ -25,6 +25,7 @@ files { ui_page "nui/radar.html" server_script 'sv_version_check.lua' +server_script 'sv_saving.lua' client_script 'config.lua' client_script 'cl_utils.lua' diff --git a/cl_radar.lua b/cl_radar.lua index d0c95d6..e876b5d 100644 --- a/cl_radar.lua +++ b/cl_radar.lua @@ -30,6 +30,23 @@ Citizen.SetTimeout( 1000, function() end ) +--[[---------------------------------------------------------------------------------- + UI loading trigger +----------------------------------------------------------------------------------]]-- +local spawned = false + +AddEventHandler( "playerSpawned", function() + if ( not spawned ) then + TriggerServerEvent( "wk:getUiData" ) + spawned = true + end +end ) + +RegisterNetEvent( "wk:loadUiData" ) +AddEventHandler( "wk:loadUiData", function( data ) + SendNUIMessage( { _type = "loadUiSettings", data = data } ) +end ) + --[[---------------------------------------------------------------------------------- Player info variables ----------------------------------------------------------------------------------]]-- @@ -1325,6 +1342,11 @@ RegisterNUICallback( "menu", function() SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } ) end ) +-- Runs when the JavaScript side sends the UI data for saving +RegisterNUICallback( "saveUiData", function( data, cb ) + TriggerServerEvent( "wk:saveUiData", data ) +end ) + --[[---------------------------------------------------------------------------------- Main threads @@ -1587,9 +1609,9 @@ function RADAR:RunControlManager() end -- Shortcut to restart the resource - --[[if ( IsDisabledControlJustPressed( 1, 167 ) ) then + if ( IsDisabledControlJustPressed( 1, 167 ) ) then ExecuteCommand( "restart wk_wars2x" ) - end]] + end end -- Control manager diff --git a/nui/radar.css b/nui/radar.css index 2bef301..ae9d1fa 100644 --- a/nui/radar.css +++ b/nui/radar.css @@ -41,7 +41,9 @@ button:focus { outline: none; } /* Settings for scaling */ transform: scale( 1.0 ); - transform-origin: 0 0; + transform-origin: 0 0; + + transition: transform 0.5s; z-index: 1; } @@ -365,7 +367,9 @@ button:focus { outline: none; } color: white; /* background-color: rgb( 50, 50, 50 ); */ - background-image: url( "images/rc_bg.png" ); + background-image: url( "images/rc_bg.png" ); + + transition: transform 0.5s; /* clip-path: polygon( 5% 0, 95% 0, 100% 25%, 90% 100%, 10% 100%, 0 25% ); */ diff --git a/nui/radar.js b/nui/radar.js index 3d77d7e..5ea42c4 100644 --- a/nui/radar.js +++ b/nui/radar.js @@ -12,6 +12,7 @@ Variables ------------------------------------------------------------------------------------*/ var resourceName; +var uiEdited = false; const audioNames = { @@ -399,16 +400,77 @@ function sendData( name, data ) { } ); } +function setUiHasBeenEdited( state ) +{ + uiEdited = state; +} + +function hasUiBeenEdited() +{ + return uiEdited; +} + +function sendSaveData() +{ + if ( hasUiBeenEdited() ) { + let data = + { + remote: { + left: elements.remote.css( "left" ), + top: elements.remote.css( "top" ), + scale: remoteScale + }, + + radar: { + left: elements.radar.css( "left" ), + top: elements.radar.css( "top" ), + scale: radarScale + }, + + safezone: safezone + } + + sendData( "saveUiData", data ); + } +} + +function loadUiSettings( data ) +{ + // Iterate through "remote" and "radar" + for ( let setting of [ "remote", "radar" ] ) + { + // Iterate through the settings + for ( let i of [ "left", "top" ] ) + { + // Update the position of the current element + elements[setting].css( i, data[setting][i] ); + } + + // Set the scale and update the display + setScaleAndDisplay( elements[setting], data[setting].scale, elements[setting + "Scaling"].display ); + } + + // Update the remote and radar scale variables + remoteScale = data.remote.scale; + radarScale = data.radar.scale; + + // Set the safezone and update the display + elements.safezoneSlider.val( data.safezone ); + elements.safezoneSlider.trigger( "input" ); +} + /*------------------------------------------------------------------------------------ UI scaling and positioning ------------------------------------------------------------------------------------*/ var remoteScale = 1.0; var remoteMoving = false; +var remoteLastOffset = [ 0, 0 ]; var remoteOffset = [ 0, 0 ]; var radarScale = 1.0; var radarMoving = false; +var radarLastOffset = [ 0, 0 ]; var radarOffset = [ 0, 0 ]; var windowWidth = 0; @@ -457,6 +519,7 @@ elements.radar.mousedown( function( event ) { } ) $( document ).mouseup( function( event ) { + // Reset the remote and radar moving variables remoteMoving = false; radarMoving = false; } ) @@ -503,6 +566,8 @@ function calculatePos( ele, x, y, w, h, offset, scale, safezone ) let eleHeight = ( ele.outerHeight() * scale ); let eleWidthPerct = ( eleWidth / w ) * 100; let eleHeightPerct = ( eleHeight / h ) * 100; + let eleWidthPerctHalf = eleWidthPerct / 2; + let eleHeightPerctHalf = eleHeightPerct / 2; let maxWidth = w - eleWidth; let maxHeight = h - eleHeight; @@ -513,18 +578,22 @@ function calculatePos( ele, x, y, w, h, offset, scale, safezone ) let leftPos = ( left / w ) * 100; let topPos = ( top / h ) * 100; + let leftLockGap = leftPos + eleWidthPerctHalf; + let topLockGap = topPos + eleHeightPerctHalf; + // Lock pos check - if ( ( leftPos + ( eleWidthPerct / 2 ) ) >= 49.0 && ( leftPos + ( eleWidthPerct / 2 ) ) <= 51.0 ) + if ( leftLockGap >= 48.0 && leftLockGap <= 52.0 ) { - leftPos = 50.0 - ( eleWidthPerct / 2 ); + leftPos = 50.0 - eleWidthPerctHalf; } - if ( ( topPos + ( eleHeightPerct / 2 ) ) >= 49.0 && ( topPos + ( eleHeightPerct / 2 ) ) <= 51.0 ) + if ( topLockGap >= 48.0 && topLockGap <= 52.0 ) { - topPos = 50.0 - ( eleHeightPerct / 2 ); + topPos = 50.0 - eleHeightPerctHalf; } updatePosition( ele, leftPos, topPos ); + setUiHasBeenEdited( true ); } function updatePosition( ele, left, top ) @@ -556,9 +625,14 @@ function hideUISettings() function changeEleScale( ele, scaleVar, amount, display ) { + // Change the scale of the element and update it's displayer let scale = changeScale( ele, scaleVar, amount ); display.html( scale.toFixed( 2 ) + "x" ); + // Tell the system the UI has been edited + // !uiEdited ? uiEdited = true : null; + setUiHasBeenEdited( true ); + return scale; } @@ -570,6 +644,12 @@ function changeScale( ele, current, amount ) return scale; } +function setScaleAndDisplay( ele, scale, display ) +{ + ele.css( "transform", "scale(" + scale + ")" ); + display.html( scale.toFixed( 2 ) + "x" ); +} + function clamp( num, min, max ) { return num < min ? min : num > max ? max : num; @@ -600,7 +680,9 @@ function closeRemote() { sendData( "closeRemote", null ); setRemoteVisible( false ); - setUISettingsVisible( false, false ); + setUISettingsVisible( false, false ); + + sendSaveData(); } $( document ).keyup( function( event ) { @@ -626,9 +708,14 @@ window.addEventListener( "message", function( event ) { switch ( type ) { case "updatePathName": resourceName = item.pathName - break; + break; + case "loadUiSettings": + loadUiSettings( item.data ); + break; case "openRemote": - setRemoteVisible( true ); + setRemoteVisible( true ); + // uiEdited = false; + setUiHasBeenEdited( false ); break; case "toggleDisplay": setRadarVisible( item.state ); diff --git a/sv_saving.lua b/sv_saving.lua new file mode 100644 index 0000000..e04f12b --- /dev/null +++ b/sv_saving.lua @@ -0,0 +1,130 @@ +--[[----------------------------------------------------------------------- + + Wraith ARS 2X + Created by WolfKnight + +-----------------------------------------------------------------------]]-- + +local DATASAVE = {} +DATASAVE.dir = "saves" + +-- Change this to whatever ID type you want to use for saving user data +-- Options are: +-- - steam +-- - license +-- - xbl +-- - live +-- - discord +-- - fivem +-- - ip +DATASAVE.idType = "license" + +-- Saves the data for the given player into the saves folder within the resource +function DATASAVE:SavePlayerData( src, data ) + -- Get the player's identifier + local id = self:GetIdentifier( src ) + + -- Save the JSON file into the saves folder + SaveResourceFile( GetCurrentResourceName(), self.dir .. "/" .. id .. ".json", json.encode( data ), -1 ) + + -- Print out a message in the console to say the player's UI data has been saved + self:Print( "Saved UI data for " .. GetPlayerName( src ) .. " (ID: " .. src .. ")" ) +end + +-- Attempts to retrieve the UI data for the given player +function DATASAVE:GetPlayerData( src ) + -- Get the player's identifier + local id = self:GetIdentifier( src ) + + -- Try to grab the raw data from the player's JSON file + local rawData = LoadResourceFile( GetCurrentResourceName(), self.dir .. "/" .. id .. ".json" ) + + -- In the event there is no file for the player, return nil + if ( rawData == nil ) then + return nil + end + + -- Decode the JSON data into a Lua table + local data = json.decode( rawData ) + + -- Return the data + return data +end + +function DATASAVE:CheckDataIsValid( data ) + -- First we check to make sure the data being passed is actually a table + if ( type( data ) ~= "table" ) then return false end + + -- Then we check to make sure that the data has only 3 elements, "remote", "radar" and "safezone" + local c = 0 + for _ in pairs( data ) do c = c + 1 end + + -- If there isn't 3 elements, then the data isn't valid + if ( c ~= 3 ) then return false end + + return true +end + +function DATASAVE:GetIdentifier( src ) + local max = GetNumPlayerIdentifiers( src ) + + for i = 0, max do + local id = GetPlayerIdentifier( src, i ) + + if ( id == nil ) then + self:Print( "^1It appears there was an error trying to find the specified ID (" .. self.idType .. ") for player " .. GetPlayerName( source ) ) + return nil + end + + if ( string.find( id, self.idType, 1 ) ) then + local split = self:SplitString( id, ":" ) + return split[2] + end + end + + return nil +end + +function DATASAVE:SplitString( inputstr, sep ) + if ( sep == nil ) then + sep = "%s" + end + + local t = {} + local i = 1 + + for str in string.gmatch( inputstr, "([^" .. sep .. "]+)" ) do + t[i] = str + i = i + 1 + end + + return t +end + +function DATASAVE:Print( msg ) + print( "^3[wk_wars2x] ^0" .. msg .. "^0" ) +end + +RegisterServerEvent( "wk:saveUiData" ) +AddEventHandler( "wk:saveUiData", function( data ) + -- Check to make sure that the data being sent by the client is valid + local valid = DATASAVE:CheckDataIsValid( data ) + + -- Only proceed if the data is actually valid + if ( valid ) then + DATASAVE:SavePlayerData( source, data ) + else + DATASAVE:Print( "^1Save data being sent from " .. GetPlayerName( source ) .. " (ID: " .. source .. ") is not valid, either something went wrong, or the player has modified the data being sent." ) + end +end ) + +RegisterServerEvent( "wk:getUiData" ) +AddEventHandler( "wk:getUiData", function() + local data = DATASAVE:GetPlayerData( source ) + + if ( data ) then + TriggerClientEvent( "wk:loadUiData", source, data ) + else + DATASAVE:Print( "Player " .. GetPlayerName( source ) .. " (ID: " .. source .. ") doesn't have a UI settings file." ) + end +end ) \ No newline at end of file