Basic plate reader working

This commit is contained in:
Dan
2020-01-27 21:54:44 +00:00
parent 1c1ea03679
commit 04e6d86318
21 changed files with 400 additions and 41 deletions

View File

@@ -77,6 +77,84 @@ Citizen.CreateThread( function()
end
end )
--[[----------------------------------------------------------------------------------
Plate reader variables
NOTE - This is not a config, do not touch anything unless you know what
you are actually doing.
----------------------------------------------------------------------------------]]--
READER = {}
READER.vars =
{
-- Whether or not the radar's UI is visible
displayed = true,
-- Whether or not the radar should be hidden, e.g. the display is active but the player then steps
-- out of their vehicle
hidden = false,
cams = {
["front"] = {
plate = nil,
index = nil
},
["rear"] = {
plate = nil,
index = nil
}
}
}
function READER:SetPlate( cam, plate )
self.vars.cams[cam].plate = plate
end
function READER:SetIndex( cam, index )
self.vars.cams[cam].index = index
end
function READER:CanPerformMainTask()
return self.vars.displayed and not self.vars.hidden
end
function READER:GetCamFromNum( relPos )
if ( relPos == 1 ) then
return "front"
elseif ( relPos == -1 ) then
return "rear"
end
end
function READER:Main()
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
for i = 1, -1, -2 do
local start = GetEntityCoords( PLY.veh )
local offset = GetOffsetFromEntityInWorldCoords( PLY.veh, 0.0, ( 50.0 * i ), 0.0 )
local veh = UTIL:GetVehicleInDirection( PLY.veh, start, offset )
if ( DoesEntityExist( veh ) and IsEntityAVehicle( veh ) ) then
local plate = GetVehicleNumberPlateText( veh )
local index = GetVehicleNumberPlateTextIndex( veh )
local cam = self:GetCamFromNum( i )
self:SetPlate( cam, plate )
self:SetIndex( cam, index )
SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } )
end
end
end
end
Citizen.CreateThread( function()
while ( true ) do
READER:Main()
Citizen.Wait( 500 )
end
end )
--[[----------------------------------------------------------------------------------
Radar variables
@@ -273,7 +351,7 @@ function RADAR:ToggleDisplayState()
self.vars.displayed = not self.vars.displayed
-- Send the toggle message to the NUI side
SendNUIMessage( { _type = "toggleDisplay", state = self:GetDisplayState() } )
SendNUIMessage( { _type = "setRadarDisplayState", state = self:GetDisplayState() } )
end
-- Gets the display state
@@ -1547,10 +1625,10 @@ end )
function RADAR:RunDisplayValidationCheck()
if ( ( ( PLY.veh == 0 or ( PLY.veh > 0 and not PLY.vehClassValid ) ) and self:GetDisplayState() and not self:GetDisplayHidden() ) or IsPauseMenuActive() and self:GetDisplayState() ) then
self:SetDisplayHidden( true )
SendNUIMessage( { _type = "toggleDisplay", state = false } )
SendNUIMessage( { _type = "setRadarDisplayState", state = false } )
elseif ( PLY.veh > 0 and PLY.vehClassValid and PLY.inDriverSeat and self:GetDisplayState() and self:GetDisplayHidden() ) then
self:SetDisplayHidden( false )
SendNUIMessage( { _type = "toggleDisplay", state = true } )
SendNUIMessage( { _type = "setRadarDisplayState", state = true } )
end
end

View File

@@ -53,7 +53,7 @@ function UTIL:Values( xs )
end
function UTIL:GetVehicleInDirection( entFrom, coordFrom, coordTo )
local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 20.0, 10, entFrom, 7 )
local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 5.0, 10, entFrom, 7 )
local _, hitEntity, endCoords, surfaceNormal, vehicle = GetShapeTestResult( rayHandle )
return vehicle
end

View File

@@ -19,6 +19,7 @@ files {
"nui/jquery-3.4.1.min.js",
"nui/radar.js",
"nui/images/*",
"nui/images/plates/*",
"nui/fonts/*",
"nui/sounds/*"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
nui/fonts/plate-font.ttf Normal file

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
nui/images/pr_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
nui/images/pr_bg.psd Normal file

Binary file not shown.

BIN
nui/images/pr_frame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
nui/images/pr_frame.psd Normal file

Binary file not shown.

View File

@@ -13,6 +13,26 @@
src: url( "fonts/Heebo-Regular.ttf" );
}
@font-face {
font-family: "Plate-Font";
src: url( "fonts/plate-font.ttf" );
}
@font-face {
font-family: "Plate-Font-Hilite";
src: url( "fonts/plate-font-hilite.ttf" );
}
@font-face {
font-family: "Plate-Font-Lolite";
src: url( "fonts/plate-font-lolite.ttf" );
}
@font-face {
font-family: "Plate-Font-Shadow";
src: url( "fonts/plate-font-Shadow.ttf" );
}
* {
font-family: 'Heebo', Verdana, Geneva, Tahoma, sans-serif;
font-size: 13px;
@@ -48,7 +68,7 @@ button:focus { outline: none; }
z-index: 1;
}
.frame_border {
#radarFrame .frame_border {
width: 685px;
height: 210px;
@@ -543,25 +563,22 @@ button:focus { outline: none; }
line-height: 62px;
}
#rc .vol_ps_container {
#rc .plate_reader_and_help_container {
width: 90%;
display: grid;
grid-template-columns: 1fr 1fr;
justify-items: center;
}
#rc .vol_ps_container .vol_and_test,
#rc .vol_ps_container .ps_blank {
#rc .plate_reader_and_help_container .plate_reader,
#rc .plate_reader_and_help_container .help {
width: 80px;
height: 55px;
border-radius: 7px;
}
#rc .vol_ps_container .hold {
border-bottom: 2px solid rgb( 0, 0, 0 );
}
#rc .vol_ps_container .ps_blank {
#rc .plate_reader_and_help_container .help {
padding: 0 10px;
font-size: 15px;
}
#rc .light {
@@ -582,9 +599,143 @@ button:focus { outline: none; }
background-color: rgb( 84, 210, 255 );
}
#plateReaderFrame {
width: 500px;
height: 200px;
position: absolute;
margin: auto;
top: calc( 50% - ( 200px / 2 ) );
left: calc( 50% - ( 500px / 2 ) );
background-image: url( "images/pr_frame.png" );
transition: transform 0.5s;
/* Settings for scaling */
transform: scale( 1.0 );
transform-origin: 0 0;
/* background-color: rgb(70, 70, 70);
box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 ); */
}
#plateReaderFrame .frame_border {
width: 465px;
height: 175px;
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgb( 20, 22, 18 );
border-radius: 5px;
/* clip-path: polygon( 20px 2px, 665px 2px, 682px 30%, 682px 70%, 665px 208px, 20px 208px, 3px 70%, 3px 30% ); */
}
#plateReader {
width: 460px;
height: 170px;
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-image: url( "images/pr_bg.png" );
box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 );
display: grid;
grid-template-rows: 30px 1fr 30px;
align-content: center;
}
#plateReader .labels {
display: grid;
grid-template-columns: 1fr 1fr;
align-content: center;
}
#plateReader .labels .title {
color: rgb( 255, 255, 255 );
}
#plateReader .labels p {
margin: 0;
text-align: center;
font-size: 18px;
}
#plateReader .plates {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
align-content: center;
justify-items: center;
}
#plateReader .plates .plate_container {
width: 90%;
height: 100%;
display: grid;
grid-template-columns: 1fr;
justify-content: center;
}
#plateReader .plates .plate_container .plate {
display: block;
max-width: 100%;
height: auto;
grid-column: 1;
grid-row: 1;
}
#plateReader .plates .plate_container .text_container {
grid-column: 1;
grid-row: 1;
display: grid;
grid-template-columns: 1fr;
justify-content: center;
}
#plateReader .plates .plate_container .text_container .text {
display: block;
font-family: "Plate-Font";
font-size: 58px;
text-align: center;
letter-spacing: -3px;
color: rgb(0, 0, 163);
padding-top: 5px;
margin: 0;
grid-column: 1;
grid-row: 1;
}
#plateReader .plates .plate_container .text_container .hilite {
font-family: "Plate-Font-Hilite";
color: rgb( 93, 65, 255 );
}
#plateReader .plates .plate_container .text_container .lolite {
font-family: "Plate-Font-Lolite";
color: rgb( 255, 255, 255 );
}
#plateReader .plates .plate_container .text_container .shadow {
font-family: "Plate-Font-Shadow";
color: rgb( 100, 100, 100 );
}
#uiSettingsBox {
width: 250px;
height: 325px;
height: 375px;
position: absolute;
margin: auto;
@@ -617,7 +768,7 @@ button:focus { outline: none; }
}
#uiSettingsBox .scaling_container {
height: 150px;
height: 225px;
display: grid;
grid-template-rows: 1fr 1fr;
}

View File

@@ -6,7 +6,6 @@
</head>
<body>
<!-- <div id="radarFrame" class="bottom_right"> -->
<div id="radarFrame">
<div class="frame_border"></div>
@@ -153,9 +152,9 @@
<button id="menuButton" data-nuitype="menu" class="circle_btn menu blue">MENU</button>
<div class="vol_ps_container">
<button id="volAndTest" class="vol_and_test blue">VOLUME <span class="hold">TEST</span></button>
<button id="psBlank" class="ps_blank blue">PS BLANK</button>
<div class="plate_reader_and_help_container">
<button id="plateReaderBtn" class="plate_reader blue">PLATE READER</button>
<button id="helpBtn" class="help blue">HELP</button>
</div>
<button id="uiSettings" class="rounded_btn light blue">UI SETTINGS</button>
@@ -163,6 +162,48 @@
<p class="logo"><span class="large">Wraith</span> ARS 2X</p>
</div>
<div id="plateReaderFrame">
<div class="frame_border"></div>
<div id="plateReader">
<div class="labels">
<p class="title">FRONT</p>
<p class="title">REAR</p>
</div>
<div class="plates">
<div class="plate_container">
<img id="frontPlate" class="plate" src="images/plates/0.png">
<div id="frontPlateText" class="text_container">
<!-- <p id="frontPlateText" class="text">46EEK872</p> -->
<p class="text">46EEK872</p>
<p class="text hilite">46EEK872</p>
<p class="text lolite">46EEK872</p>
<p class="text shadow">46EEK872</p>
</div>
</div>
<div class="plate_container">
<img id="rearPlate" class="plate" src="images/plates/0.png">
<div id="rearPlateText" class="text_container">
<!-- <p id="rearPlateText" class="text">46EEK872</p> -->
<p class="text">46EEK872</p>
<p class="text hilite">46EEK872</p>
<p class="text lolite">46EEK872</p>
<p class="text shadow">46EEK872</p>
</div>
</div>
</div>
<div class="labels">
<p>LOCKED</p>
<p>LOCKED</p>
</div>
</div>
</div>
<div id="uiSettingsBox">
<div class="radar_settings">
<p class="title">UI Settings</p>
@@ -190,6 +231,17 @@
<div id="remoteIncreaseScale" class="symbol plus"></div>
</div>
<div class="scaling">
<div id="readerDecreaseScale" class="symbol minus"></div>
<div class="info">
<p>Reader Scale</p>
<p id="readerScaleDisplay" class="multiplier">1.00x</p>
</div>
<div id="readerIncreaseScale" class="symbol plus"></div>
</div>
</div>
<div class="safezone_container">

View File

@@ -48,6 +48,8 @@ const elements =
{
radar: $( "#radarFrame" ),
remote: $( "#rc" ),
plateReader: $( "#plateReaderFrame" ),
toggleDisplay: $( "#toggleDisplay" ),
pwrBtn: $( "#pwrBtn" ),
@@ -67,6 +69,24 @@ const elements =
display: $( "#remoteScaleDisplay" )
},
plateReaderScaling: {
increase: $( "#readerIncreaseScale" ),
decrease: $( "#readerDecreaseScale" ),
display: $( "#readerScaleDisplay" )
},
plates: {
front: {
text: $( "#frontPlateText" ),
img: $( "#frontPlate" )
},
rear: {
text: $( "#rearPlateText" ),
img: $( "#rearPlate" )
}
},
safezoneSlider: $( "#safezone" ),
safezoneDisplay: $( "#safezoneDisplay" ),
@@ -147,6 +167,7 @@ const dirs =
------------------------------------------------------------------------------------*/
elements.radar.hide();
elements.remote.hide();
// elements.plateReader.hide();
elements.uiSettingsBox.hide();
elements.keyLock.label.hide();
@@ -172,6 +193,11 @@ function setRemoteVisible( state )
state ? elements.remote.fadeIn() : elements.remote.fadeOut();
}
function setPlateReaderVisible( state )
{
state ? elements.plateReader.fadeIn() : elements.plateReader.fadeOut();
}
function setLight( ant, cat, item, state )
{
let obj = elements.antennas[ant][cat][item];
@@ -221,6 +247,15 @@ function setAntennaDirs( ant, dir, fastDir )
setLight( ant, "dirs", "bwdFast", fastDir == dirs.away );
}
function setPlate( cam, plate, index )
{
elements.plates[cam].img.attr( "src", "images/plates/" + index + ".png" );
elements.plates[cam].text.find( "p" ).each( function( i, obj ) {
$( this ).html( plate );
} );
}
/*------------------------------------------------------------------------------------
Clearing functions
@@ -427,6 +462,12 @@ function sendSaveData()
scale: radarScale
},
plateReader: {
left: elements.plateReader.css( "left" ),
top: elements.plateReader.css( "top" ),
scale: readerScale
},
safezone: safezone
}
@@ -436,8 +477,8 @@ function sendSaveData()
function loadUiSettings( data )
{
// Iterate through "remote" and "radar"
for ( let setting of [ "remote", "radar" ] )
// Iterate through "remote", "radar" and "plateReader"
for ( let setting of [ "remote", "radar", "plateReader" ] )
{
// Iterate through the settings
for ( let i of [ "left", "top" ] )
@@ -450,9 +491,10 @@ function loadUiSettings( data )
setScaleAndDisplay( elements[setting], data[setting].scale, elements[setting + "Scaling"].display );
}
// Update the remote and radar scale variables
// Update the remote, radar and reader scale variables
remoteScale = data.remote.scale;
radarScale = data.radar.scale;
readerScale = data.plateReader.scale;
// Set the safezone and update the display
elements.safezoneSlider.val( data.safezone );
@@ -465,21 +507,23 @@ function loadUiSettings( data )
------------------------------------------------------------------------------------*/
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 readerScale = 1.0;
var readerMoving = false;
var readerOffset = [ 0, 0 ];
var windowWidth = 0;
var windowHeight = 0;
var safezone = 0;
// Close the UI settings window when the 'Close' button is pressed
elements.closeUiBtn.click( function() {
setUISettingsVisible( false, true );
setUISettingsVisible( false );
} )
// Set the remote scale buttons to change the remote's scale
@@ -500,6 +544,15 @@ elements.radarScaling.decrease.click( function() {
radarScale = changeEleScale( elements.radar, radarScale, -0.05, elements.radarScaling.display );
} )
// Set the reader scale buttons to change the reader's scale
elements.plateReaderScaling.increase.click( function() {
readerScale = changeEleScale( elements.plateReader, readerScale, 0.05, elements.plateReaderScaling.display );
} )
elements.plateReaderScaling.decrease.click( function() {
readerScale = changeEleScale( elements.plateReader, readerScale, -0.05, elements.plateReaderScaling.display );
} )
// Remote mouse down and up event
elements.remote.mousedown( function( event ) {
remoteMoving = true;
@@ -518,10 +571,20 @@ elements.radar.mousedown( function( event ) {
radarOffset = getOffset( offset, event.clientX, event.clientY );
} )
// Plate reader mouse down and up event
elements.plateReader.mousedown( function( event ) {
readerMoving = true;
let offset = $( this ).offset();
readerOffset = getOffset( offset, event.clientX, event.clientY );
} )
$( document ).mouseup( function( event ) {
// Reset the remote and radar moving variables
remoteMoving = false;
radarMoving = false;
readerMoving = false;
} )
$( document ).mousemove( function( event ) {
@@ -541,6 +604,13 @@ $( document ).mousemove( function( event ) {
calculatePos( elements.radar, x, y, windowWidth, windowHeight, radarOffset, radarScale, safezone );
}
if ( readerMoving )
{
event.preventDefault();
calculatePos( elements.plateReader, x, y, windowWidth, windowHeight, readerOffset, readerScale, safezone );
}
} )
$( window ).resize( function() {
@@ -582,12 +652,12 @@ function calculatePos( ele, x, y, w, h, offset, scale, safezone )
let topLockGap = topPos + eleHeightPerctHalf;
// Lock pos check
if ( leftLockGap >= 48.0 && leftLockGap <= 52.0 )
if ( leftLockGap >= 49.0 && leftLockGap <= 51.0 )
{
leftPos = 50.0 - eleWidthPerctHalf;
}
if ( topLockGap >= 48.0 && topLockGap <= 52.0 )
if ( topLockGap >= 49.0 && topLockGap <= 51.0 )
{
topPos = 50.0 - eleHeightPerctHalf;
}
@@ -610,10 +680,9 @@ function getOffset( offset, x, y )
]
}
function setUISettingsVisible( state, remote )
function setUISettingsVisible( state )
{
state ? elements.uiSettingsBox.fadeIn() : elements.uiSettingsBox.fadeOut();
// if ( remote ) { setRemoteVisible( !state ); }
}
function hideUISettings()
@@ -630,7 +699,6 @@ function changeEleScale( ele, scaleVar, amount, display )
display.html( scale.toFixed( 2 ) + "x" );
// Tell the system the UI has been edited
// !uiEdited ? uiEdited = true : null;
setUiHasBeenEdited( true );
return scale;
@@ -680,7 +748,7 @@ function closeRemote()
{
sendData( "closeRemote", null );
setRemoteVisible( false );
setUISettingsVisible( false, false );
setUISettingsVisible( false );
sendSaveData();
}
@@ -714,10 +782,9 @@ window.addEventListener( "message", function( event ) {
break;
case "openRemote":
setRemoteVisible( true );
// uiEdited = false;
setUiHasBeenEdited( false );
break;
case "toggleDisplay":
case "setRadarDisplayState":
setRadarVisible( item.state );
break;
case "radarPower":
@@ -755,6 +822,9 @@ window.addEventListener( "message", function( event ) {
break;
case "displayKeyLock":
displayKeyLock( item.state );
break;
case "changePlate":
setPlate( item.cam, item.plate, item.index );
break;
default:
break;

View File

@@ -51,31 +51,38 @@ function DATASAVE:GetPlayerData( src )
return data
end
-- Checks that the given data is valid, helps to stop modified data from being sent through the save system
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"
-- Then we check to make sure that the data has only 3 elements, "remote", "radar", "reader" 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
-- If there isn't 4 elements, then the data isn't valid
if ( c ~= 4 ) then return false end
return true
end
-- Gets the identifier for the given player based on the identifier type specified at the top
function DATASAVE:GetIdentifier( src )
-- Get the number of identifiers the player has
local max = GetNumPlayerIdentifiers( src )
-- Iterate through the identifier numerical range
for i = 0, max do
-- Get the current identifier
local id = GetPlayerIdentifier( src, i )
-- In the event the identifier is nil, report it to the server console and return nil
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]