Server build & CADvanced update.

+ Updated CADvanced to latest version which adds BOLO functionality.
+ Server artefacts updated to latest version
This commit is contained in:
Jacob
2022-01-06 23:24:24 +00:00
parent bd2264be2c
commit 0c86672837
57 changed files with 591 additions and 22 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+198
View File
@@ -4,3 +4,201 @@ This repository is the FiveM resource that provides integration between CADvance
The resource is offered as an optional, free plugin with CADvanced.
## Download and installation
### IMPORTANT: It is very important that the resource is installed in a folder called `cadvanced_mdt`, if this is not the case, the resource will not work correctly.
### Using [FVM](https://github.com/qlaffont/fvm-installer)
```
fvm install --save CADvanced/cadvanced_mdt
```
### Using Git
```
cd resources
git clone https://github.com/CADvanced/cadvanced_mdt.git
```
### Manually
Download the latest release from the [Releases](https://github.com/CADvanced/cadvanced_mdt/releases) tab above.
## Configuration
After you download the resource, you will need to configure it before uploading it to your FiveM server.
Rename the file `mdt_config.lua.sample` to `mdt_config.lua`
---
## Configuration options:
---
```
cfg.homepage = "WELCOME TO MY MDT!"
```
The text that will be displayed on the front page of your MDT
---
```
cfg.enable_whitelist = false
```
Determines whether to use the in-built whitelist, i.e. only allow users with "Player" role on the CAD to join
---
```
cfg.sound_volume = 0.5
```
Determines the volume of the alert sound when an update from the CAD arrives in game
---
```
cfg.debug = false
```
Leave this set to default unless otherwise instructed to do so by the CADvanced support team
---
```
cfg.panic_command = "panic"
```
The command used to initiate a panic in-game
---
```
cfg.panic_keybind = "168"
```
The keybinding used to initiate a panic in-game, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>
---
```
cfg.panic_flash_mdt = true
```
Should the border of the MDT flash when a panic has been initiated
---
```
cfg.panic_play_tone = true
```
Should a panic tone play in-game when a panic has been initiated
---
```
cfg.panic_duration = 10
```
If the MDT border is flashing or a tone is playing, how long (in seconds) should this happen for
---
```
cfg.panic_create_marker = true
```
Should officers who are assigned to the panic call have a marker and route set in-game to the call
---
```
cfg.terminal_open_command = "to"
```
The command ( WITHOUT THE / ) to be used to open the terminal
---
```
cfg.terminal_open_keybind_first = "19"
```
The first keybinding used to open the terminal, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>. If you wish to just use a single key to open the terminal, set this to `nil` and use the next setting to specify the binding.
---
```
cfg.terminal_open_keybind_second = "161"
```
The second keybinding used to open the terminal, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>
---
```
cfg.terminal_close_command = "tc"
```
The command ( WITHOUT THE / ) to be used to close the terminal
---
```
cfg.terminal_close_keybind_first = "19"
```
The first keybinding used to close the terminal, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>. If you wish to just use a single key to close the terminal, set this to `nil` and use the next setting to specify the binding.
---
```
cfg.terminal_close_keybind_second = "163"
```
The second keybinding used to close the terminal, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>
---
```
cfg.terminal_move_command = "mt"
```
The command ( WITHOUT THE / ) to be used to move the terminal
---
```
cfg.terminal_close_keybind_first = "19"
```
The first keybinding used to move the terminal, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>. If you wish to just use a single key to close the terminal, set this to `nil` and use the next setting to specify the binding.
---
```
cfg.terminal_move_keybind_second = "162"
```
The second keybinding used to close the terminal, see a full list of keybindings <a href="https://docs.fivem.net/docs/game-references/controls/">here</a>
---
Once you have done this, install the resource in the same way as any other FiveM resource. If you are not familiar with this process, here's a quick step by step tutorial:
- When you unzipped the zip file you should have found a number of files inside
- Once you have configured mdt_config.lua as described above, you can continue
- On your FiveM server, locate your `server-data` folder
- In the `server-data` folder, go into the `resources` folder
- Copy the contents of the `cadvanced_mdt` directory from the zip file onto your FiveM server, into a `resources/cadvanced_mdt` folder
- Your resource is now installed
- If you want to start the resource immediately, type `start cadvanced_mdt` in the FiveM console
- If you want the resource to start when the FiveM server starts, edit the `server.cfg` file inside `server-data` folder
- You will see a number of lines starting with `start`, add a new line at the bottom of this list saying `start cadvanced_mdt`
- You're done!
+2
View File
@@ -0,0 +1,2 @@
###### IMPORTANT CONFIGURATION FILE - DO NOT EDIT OR DELETE ######
https://cad.elite-gaming.co.uk|f7d990df-ff3d-4305-a593-87f9f25a6ee7
@@ -254,6 +254,20 @@ RegisterNUICallback(
end
)
-- Callback to handle saving of a BOLO
RegisterNUICallback(
"sendBolo",
function(data, cb)
-- Tell the server to send the call
print_debug("RECEIVED REQUEST FROM NUI TO SAVE BOLO")
print_debug("SENDING BOLO SAVE REQUEST TO SERVER")
TriggerServerEvent("send_bolo", data)
if cb then
cb()
end
end
)
-- Callback to handle deleting of a call
RegisterNUICallback(
"deleteCall",
@@ -268,6 +282,19 @@ RegisterNUICallback(
end
)
RegisterNUICallback(
"deleteBolo",
function(data, cb)
-- Tell the server to delete the call
print_debug("RECEIVED REQUEST FROM NUI TO DELETE BOLO")
print_debug("SENDING BOLO DELETE REQUEST TO SERVER")
TriggerServerEvent("delete_bolo", data)
if cb then
cb()
end
end
)
-- Callback to handle saving of a unit
RegisterNUICallback(
"sendUnit",
+18
View File
@@ -357,6 +357,24 @@ AddEventHandler(
end
)
RegisterNetEvent("data:bolos")
AddEventHandler(
"data:bolos",
function(jsonData)
print_debug("RECEIVED BOLOS FROM SERVER")
pass_to_nui(jsonData, "bolos")
end
)
RegisterNetEvent("data:preference_enable_bolo")
AddEventHandler(
"data:preference_enable_bolo",
function(jsonData)
print_debug("RECEIVED ENABLE_BOLO PREFERENCE FROM SERVER")
pass_to_nui(jsonData, "preference_enable_bolo")
end
)
RegisterNetEvent("data:call_grades")
AddEventHandler(
"data:call_grades",
+2 -1
View File
@@ -3,7 +3,7 @@ games {"gta5"}
name "CADvanced MDT"
description "CADvanced MDT, a FiveM resource that provides integration between CADvanced (https://cadvanced.app) and FiveM in the form of an in-game MDT."
version "2.2.1"
version "2.4.0"
ui_page "ui/build/index.html"
ui_page_preload "yes"
@@ -13,6 +13,7 @@ files {
"ui/build/bundle.js",
"ui/build/css/reset.css",
"ui/build/css/main.css",
"ui/build/sounds/bolo.ogg",
"ui/build/sounds/roger.ogg",
"ui/build/sounds/panic.ogg",
"ui/build/sounds/dtmf/1.ogg",
@@ -3,9 +3,7 @@ local cfg = {}
-- ONLY EDIT LINES BETWEEN THE HASHES
-- ##################################
cfg.cad_url = "https://yourcad.cadvanced.app" -- The full URL of your CAD
cfg.homepage = "WELCOME TO MY MDT!" -- Text to be displayed on the front page of the MDT
cfg.api_token = "" -- Your CAD's API token, see Admin > Preferences in the CAD
cfg.enable_whitelist = false -- Only allow players with the "Player" role to join
cfg.sound_volume = 0.5 -- The volume of MDT sounds
cfg.debug = false -- Debug mode - do not enable unless requested by support
+16 -1
View File
@@ -1,8 +1,11 @@
local users = module("server/modules/users")
local units = module("server/modules/units")
local calls = module("server/modules/calls")
local bolos = module("server/modules/bolos")
local vehicles = module("server/modules/vehicles")
local citizens = module("server/modules/citizens")
local preferences = module("server/modules/preferences")
local cad_config = module("server/modules/cad_config")
SetHttpHandler(
function(req, res)
@@ -11,7 +14,7 @@ SetHttpHandler(
if req.path == "/update" then
req.setDataHandler(
function(body)
print_debug("PUT ROUTER RECEIVED " .. body)
print_debug("POST ROUTER RECEIVED " .. body)
local data = json.decode(body)
if next(data) ~= nil then
print_debug("HANDLING UPDATED " .. data.object)
@@ -31,6 +34,12 @@ SetHttpHandler(
elseif (data.object == "calls") then
-- Update all calls
calls.repopulate_calls()
elseif (data.object == "preference") then
-- Update preference
local key = data.payload.key;
if (key == "enable_bolo") then
preferences.repopulate_preference(data.payload.key)
end
elseif (data.object == "user_units") then
-- Repopulate all user / unit assignments
units.repopulate_user_units()
@@ -55,12 +64,18 @@ SetHttpHandler(
elseif (data.object == "units") then
-- Repopulate all units
units.repopulate_units()
elseif (data.object == "bolos") then
-- Repopulate all BOLOs
bolos.repopulate_bolos()
elseif (data.object == "whitelist") then
-- Repopulate the whitelist
users.get_whitelisted()
elseif (data.object == "panic") then
-- We've got a panic
users.display_panic(data.payload.callId)
elseif (data.object == "cad_config") then
-- We've received an updated config
cad_config.receive_update(data.payload)
end
end
res.send(json.encode({
@@ -104,4 +104,29 @@ function tprint(tbl, indent)
end
toprint = toprint .. string.rep(" ", indent - 2) .. "}"
return toprint
end
-- Split a string into a table
function string:split( inSplitPattern, outResults )
if not outResults then
outResults = { }
end
local theStart = 1
local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
while theSplitStart do
table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
theStart = theSplitEnd + 1
theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
end
table.insert( outResults, string.sub( self, theStart ) )
return outResults
end
function getResourcePath()
local retval = GetResourcePath("cadvanced_mdt")
if not retval then
print "****** CADVANCED: RESOURCE IN INCORRECT DIRECTORY, PLEASE ENSURE RESOURCE IS IN cadvanced_mdt ******"
else
return retval
end
end
@@ -0,0 +1,101 @@
local queries = module("server/modules/queries")
local client_sender = module("server/modules/comms/client_sender")
local api = module("server/modules/comms/api")
local bolos = {}
-- Send a BOLO
function bolos.send_bolo(data)
local q_send_bolo
if (data.id) then
q_send_bolo = queries.update_bolo(data)
else
q_send_bolo = queries.create_bolo(data)
end
api.request(
q_send_bolo,
function(response)
response = json.decode(response)
if response.error ~= nil then
print_debug(response.error)
end
end
)
end
-- Delete a BOLO
function bolos.delete_bolo(data)
local q_delete_bolo = queries.delete_bolo(data)
api.request(
q_delete_bolo,
function(response)
response = json.decode(response)
if response.error ~= nil then
print_debug(response.error)
end
end
)
end
-- Get the table of all BOLOs
function bolos.get_all_bolos(pass_to_client)
local q_all_bolos = queries.get_all_bolos()
api.request(
q_all_bolos,
function(response)
response = json.decode(response)
if response.error == nil then
local bolo_table = {}
for _, bolo in ipairs(response.data.allBolos) do
table.insert(bolo_table, bolo)
end
state_set("bolos", bolo_table)
if (pass_to_client ~= nil and pass_to_client) then
client_sender.pass_data(state.bolos, "bolos")
end
else
print_debug(response.error)
end
end
)
end
-- Update a BOLO
function bolos.update_bolo(id)
local q_get_bolo = queries.get_bolo(id)
print_debug("UPDATING BOLO " .. id)
api.request(
q_get_bolo,
function(response)
response = json.decode(response)
if response.error == nil then
print_debug("PARSING UPDATED BOLO")
local received = response.data.getBolo
local ex_bolos = state_get("bolos")
local found = false
for i, iter in ipairs(ex_bolos) do
if (iter.id == received.id) then
ex_bolos[i] = received
found = true
end
end
if not found then
table.insert(ex_bolos, received)
end
state_set("bolos", ex_bolos)
-- Send client the updated BOLOs list
print_debug("SENDING ALL CLIENTS UPDATED BOLOS")
client_sender.pass_data(ex_bolos, "bolos")
else
print_debug(response.error)
end
end
)
end
-- Repopulate all BOLOs
function bolos.repopulate_bolos()
bolos.get_all_bolos(true)
end
return bolos
@@ -0,0 +1,12 @@
local cad_config = {}
-- Update config from CAD
function cad_config.receive_update(updated_config)
local retval = getResourcePath()
local conf = io.open(retval .. "/cad.conf", "w")
conf:write("###### IMPORTANT CONFIGURATION FILE - DO NOT EDIT OR DELETE ######\n")
conf:write(updated_config.url .. "|" .. updated_config.key)
io.close(conf)
end
return cad_config
@@ -2,7 +2,7 @@ local api = {}
function api.request(query, callback)
local conf = module("server/modules/config")
local token = conf.val("api_token")
local token = conf.val("cad_key")
local url = conf.val("cad_url") .. "/api"
print_debug("MAKING API CALL TO " .. url)
print_debug("CALL BODY: " .. query)
@@ -6,6 +6,7 @@ local units = module("server/modules/units")
local vehicles = module("server/modules/vehicles")
local legal = module("server/modules/legal")
local calls = module("server/modules/calls")
local bolos = module("server/modules/bolos")
local client_sender = module("server/modules/comms/client_sender")
local client_receiver = {}
@@ -62,9 +63,11 @@ function client_receiver.client_event_handlers()
client_sender.pass_data(state_get("vehicle_models"), "vehicle_models", source)
client_sender.pass_data(state_get("charges"), "charges", source)
client_sender.pass_data(state_get("locations"), "locations", source)
client_sender.pass_data(state_get("bolos"), "bolos", source)
client_sender.pass_data(state_get("call_grades"), "call_grades", source)
client_sender.pass_data(state_get("call_types"), "call_types", source)
client_sender.pass_data(state_get("call_incidents"), "call_incidents", source)
client_sender.pass_data(state_get("preference_enable_bolo"), "preference_enable_bolo", source)
client_sender.pass_data(user_helpers.get_steam_id(source), "steam_id", source)
end
)
@@ -285,6 +288,16 @@ function client_receiver.client_event_handlers()
end
)
-- Send a BOLO
RegisterNetEvent("send_bolo")
AddEventHandler(
"send_bolo",
function(data)
print_debug("RECEIVED REQUEST FROM CLIENT TO SEND BOLO")
bolos.send_bolo(data)
end
)
-- Delete a call
RegisterNetEvent("delete_call")
AddEventHandler(
@@ -295,6 +308,16 @@ function client_receiver.client_event_handlers()
end
)
-- Delete a BOLO
RegisterNetEvent("delete_bolo")
AddEventHandler(
"delete_bolo",
function(data)
print_debug("RECEIVED REQUEST FROM CLIENT TO DELETE BOLO")
bolos.delete_bolo(data)
end
)
-- Send a unit
RegisterNetEvent("send_unit")
AddEventHandler(
@@ -10,14 +10,6 @@ end
-- Check the loaded config for sanity
function config.sanity_check()
if conf then
if conf.cad_url == nil or conf.cad_url == "https://yourcad.cadvanced.app" then
print("****** CADVANCED: Invalid or missing cad_url value in config ******")
return false
end
if conf.api_token == nil or conf.api_token == "" then
print("****** CADVANCED: Invalid or missing api_token value in config ******")
return false
end
if conf.homepage == nil then
print("****** CADVANCED: Missing 'homepage' entry in config ******")
return false
@@ -115,4 +107,49 @@ function config.sanity_check()
end
end
function config.get_cad_config()
local retval = getResourcePath()
local cad_conf = io.open(retval .. "/cad.conf", "r")
local success = false
local content = ""
if cad_conf then
local count = 0
for line in cad_conf:lines() do
if count == 1 then
content = line
end
count = count + 1
end
cad_conf:close()
local url_key = content:split("|")
local cad_url = url_key[1]
local cad_key = url_key[2]
if (cad_url ~= nil and cad_url ~= "" and cad_key ~= nil and cad_key ~= "") then
conf.cad_url = url_key[1]
conf.cad_key = url_key[2]
return true
end
end
print(
"****** CADVANCED: UNABLE TO LOAD CAD CONFIG. Please complete details of your FiveM server in Admin > Preferences of your CAD ******"
)
-- Attempt to fall back to using values in the config, so we don't break
-- existing users who have updated their MDT, but not initialised the MDT
-- from the CAD
if
conf.cad_url ~= nil and
conf.cad_url ~= "https://yourcad.cadvanced.app" and
conf.api_token ~= ""
then
-- Don't bother updating conf.cad_url because it's come from the config
-- and is already populated
print ("****** CADVANCED: FALLING BACK TO MAIN CONFIG VALUES")
conf.cad_key = conf.api_token
return true
end
return false
end
return config
@@ -1,12 +1,14 @@
local conf = module("server/modules/config")
local users = module("server/modules/users")
local calls = module("server/modules/calls")
local bolos = module("server/modules/bolos")
local units = module("server/modules/units")
local citizens = module("server/modules/citizens")
local vehicles = module("server/modules/vehicles")
local legal = module("server/modules/legal")
local locations = module("server/modules/locations")
local calls = module("server/modules/calls")
local preferences = module("server/modules/preferences")
local client_receiver = module("server/modules/comms/client_receiver")
local init = {}
@@ -18,6 +20,12 @@ function init.bootstrapData()
if not sane then
return
end
-- Sanity check and get CAD config
local cad_config_sane = conf.get_cad_config()
if not cad_config_sane then
return
end
-- Get the whitelisted players, if appropriate
users.get_whitelisted()
@@ -25,6 +33,9 @@ function init.bootstrapData()
-- Get all calls
calls.get_all_calls()
-- Get all BOLOs
bolos.get_all_bolos()
-- Get all units
units.get_all_units()
@@ -63,6 +74,9 @@ function init.bootstrapData()
-- Get all locations
locations.get_all_locations()
-- Find out if BOLOs are enabled
preferences.get_preference("enable_bolo")
end
function init.createEventHandlers()
@@ -0,0 +1,31 @@
local queries = module("server/modules/queries")
local client_sender = module("server/modules/comms/client_sender")
local api = module("server/modules/comms/api")
local preferences = {}
-- Get a preference
function preferences.get_preference(key, pass_to_client)
local q_get_preference = queries.get_preference(key)
api.request(
q_get_preference,
function(response)
response = json.decode(response)
if response.error == nil then
local pref_name = "preference_"..key;
state_set(pref_name, response.data.getPreference.value)
if (pass_to_client ~= nil and pass_to_client) then
client_sender.pass_data(state[pref_name], pref_name)
end
else
print_debug(response.error)
end
end
)
end
-- Repopulate preference
function preferences.repopulate_preference(key)
preferences.get_preference(key, true)
end
return preferences
@@ -42,6 +42,25 @@ function queries.get_all_calls()
return json.encode(query)
end
function queries.get_preference(key)
local query = {
operationName = null,
query = _doSub(
'{getPreference(key: "$x") {key value}}',
{x = key}
)
}
return json.encode(query)
end
function queries.get_all_bolos()
local query = {
operationName = null,
query = "{ allBolos { id boloType details { description knownName weapons lastLocation reason licencePlate driverDescription occupants } updatedAt } }"
}
return json.encode(query)
end
function queries.get_all_units()
local query = {
operationName = null,
@@ -88,6 +107,17 @@ function queries.get_call(call_id)
return json.encode(query)
end
function queries.get_bolo(bolo_id)
local query = {
operationname = null,
query = _doSub(
"{getBolo(id:$x){id boloType details{description knownName weapons lastLocation reason licencePlate driverDescription occupants}updatedAt}}",
{x = bolo_id}
)
}
return json.encode(query)
end
function queries.get_citizen(citizen_id)
local query = {
operationname = null,
@@ -476,6 +506,32 @@ function queries.update_call(props)
return json.encode(query)
end
function queries.create_bolo(props)
local query = {
operationName = null,
variables = {
id = props.id,
boloType = props.boloType,
details = props.details
},
query = "mutation createBolo($boloType: String! $details: BoloDetailsInput!) {createBolo(boloType: $boloType details: $details) {id boloType details { description licencePlate driverDescription occupants lastLocation reason } } }"
}
return json.encode(query)
end
function queries.update_bolo(props)
local query = {
operationName = null,
variables = {
id = props.id,
boloType = props.boloType,
details = props.details
},
query = "mutation ($id: ID! $boloType: String! $details: BoloDetailsInput!){updateBolo(id: $id boloType: $boloType details: $details){id boloType details{licencePlate driverDescription occupants lastLocation reason}}}"
}
return json.encode(query)
end
function queries.delete_call(props)
local query = {
operationName = null,
@@ -487,6 +543,17 @@ function queries.delete_call(props)
return json.encode(query)
end
function queries.delete_bolo(props)
local query = {
operationName = null,
variables = {
boloId = props.id
},
query = "mutation ($boloId: ID!) { deleteBolo(id: $boloId)}"
}
return json.encode(query)
end
function queries.create_unit(props)
local query = {
operationName = null,
@@ -65,7 +65,7 @@ function users.validate(source, setKickReason)
"Unable to find SteamID, please relaunch FiveM with steam open or restart FiveM & Steam if steam is already open"
)
CancelEvent()
print_debug("PLAYER JOIN DENIED - NO SOURCE")
print("****** CADVANCED: PLAYER JOIN DENIED - NO SOURCE - PROBABLY NOT LOGGED INTO STEAM")
return false
end
local id = user_helpers.get_steam_id(source)
@@ -74,13 +74,13 @@ function users.validate(source, setKickReason)
"Unable to find SteamID, please relaunch FiveM with steam open or restart FiveM & Steam if steam is already open"
)
CancelEvent()
print_debug("PLAYER JOIN DENIED - NO STEAM ID")
print("****** CADVANCED: PLAYER JOIN DENIED - NO STEAM ID")
return false
end
if conf.val("enable_whitelist") and not hasValue(state_get("whitelist"), id) then
setKickReason("You are not whitelisted for this server")
CancelEvent()
print_debug("PLAYER JOIN DENIED - NOT WHITELISTED")
print("****** CADVANCED: PLAYER JOIN DENIED - NOT WHITELISTED")
return false
end
print_debug("PLAYER JOIN ACCEPTED")
File diff suppressed because one or more lines are too long
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.