-
-
diff --git a/resources/[sonorancad]/sonorancad/core/client_nui/js/http.js b/resources/[sonorancad]/sonorancad/core/client_nui/js/http.js
deleted file mode 100644
index 205b3fccd..000000000
--- a/resources/[sonorancad]/sonorancad/core/client_nui/js/http.js
+++ /dev/null
@@ -1,7 +0,0 @@
-$(function () {
- window.addEventListener('message', function (event) {
- if (event.data.type == "light_event") {
- $.post("http://localhost:" + event.data.port + "/lighting", JSON.stringify({ state: event.data.event }))
- }
- });
-});
\ No newline at end of file
diff --git a/resources/[sonorancad]/sonorancad/core/client_nui/sounds/beeps.mp3 b/resources/[sonorancad]/sonorancad/core/client_nui/sounds/beeps.mp3
deleted file mode 100644
index 915f2b964..000000000
Binary files a/resources/[sonorancad]/sonorancad/core/client_nui/sounds/beeps.mp3 and /dev/null differ
diff --git a/resources/[sonorancad]/sonorancad/core/commands.lua b/resources/[sonorancad]/sonorancad/core/commands.lua
deleted file mode 100644
index 9d93cb19f..000000000
--- a/resources/[sonorancad]/sonorancad/core/commands.lua
+++ /dev/null
@@ -1,245 +0,0 @@
---[[
- SonoranCAD FiveM Integration
-
- Commands Module
-
- Provides /sonoran command for console control
-]]
-
---[[ /sonoran
- debugmode - old caddebug toggle
- info - dump version info, configuration
- support - dump useful data for support staff
- verify - run hash checks to confirm all files are untampered
- plugin
-
-[](https://travis-ci.org/petkaantonov/bluebird)
-[](http://petkaantonov.github.io/bluebird/coverage/debug/index.html)
-
-**Got a question?** Join us on [stackoverflow](http://stackoverflow.com/questions/tagged/bluebird), the [mailing list](https://groups.google.com/forum/#!forum/bluebird-js) or chat on [IRC](https://webchat.freenode.net/?channels=#promises)
-
-# Introduction
-
-Bluebird is a fully featured promise library with focus on innovative features and performance
-
-See the [**bluebird website**](http://bluebirdjs.com/docs/getting-started.html) for further documentation, references and instructions. See the [**API reference**](http://bluebirdjs.com/docs/api-reference.html) here.
-
-For bluebird 2.x documentation and files, see the [2.x tree](https://github.com/petkaantonov/bluebird/tree/2.x).
-
-# Questions and issues
-
-The [github issue tracker](https://github.com/petkaantonov/bluebird/issues) is **_only_** for bug reports and feature requests. Anything else, such as questions for help in using the library, should be posted in [StackOverflow](http://stackoverflow.com/questions/tagged/bluebird) under tags `promise` and `bluebird`.
-
-
-
-## Thanks
-
-Thanks to BrowserStack for providing us with a free account which lets us support old browsers like IE8.
-
-# License
-
-The MIT License (MIT)
-
-Copyright (c) 2013-2016 Petka Antonov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
diff --git a/resources/[sonorancad]/sonorancad/node_modules/bluebird/changelog.md b/resources/[sonorancad]/sonorancad/node_modules/bluebird/changelog.md
deleted file mode 100644
index 73b2eb6c7..000000000
--- a/resources/[sonorancad]/sonorancad/node_modules/bluebird/changelog.md
+++ /dev/null
@@ -1 +0,0 @@
-[http://bluebirdjs.com/docs/changelog.html](http://bluebirdjs.com/docs/changelog.html)
diff --git a/resources/[sonorancad]/sonorancad/node_modules/bluebird/js/browser/bluebird.core.js b/resources/[sonorancad]/sonorancad/node_modules/bluebird/js/browser/bluebird.core.js
deleted file mode 100644
index ffb653822..000000000
--- a/resources/[sonorancad]/sonorancad/node_modules/bluebird/js/browser/bluebird.core.js
+++ /dev/null
@@ -1,3739 +0,0 @@
-/* @preserve
- * The MIT License (MIT)
- *
- * Copyright (c) 2013-2015 Petka Antonov
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-/**
- * bluebird build version 3.4.7
- * Features enabled: core
- * Features disabled: race, call_get, generators, map, nodeify, promisify, props, reduce, settle, some, using, timers, filter, any, each
-*/
-!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Promise=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof _dereq_=="function"&&_dereq_;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof _dereq_=="function"&&_dereq_;for(var o=0;oPlayer ID: %s
Name: %s
Date of Birth: %s
"):format(char.img, target, name, dob), - type = "success", - layout = "bottomcenter", - timeout = "10000" - }) - end - end - end) - end) - - if pluginConfig.allowCustomIds then - RegisterCommand("setid", function(source, args, rawCommand) - TriggerClientEvent("SonoranCAD::civintegration:SetCustomId", source) - end) - - RegisterCommand("resetid", function(source, args, rawCommand) - if CustomCharacterCache[source] ~= nil then - CustomCharacterCache[source] = nil - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^2OK ^0] ", "Custom character removed."}}) - end - end) - - RegisterNetEvent("SonoranCAD::civintegration:SetCustomId") - AddEventHandler("SonoranCAD::civintegration:SetCustomId", function(id) - CustomCharacterCache[source] = {{ ['first'] = id.first, ['last'] = id.last, ['dob'] = id.dob, img = "https://sonorancad.com/statics/images/blank_user.jpg" }} - end) - end - - if pluginConfig.allowPurge then - RegisterCommand("refreshid", function(source, args, rawCommand) - CharacterCacheTimers[source] = 0 - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^2OK ^0] ", "Reset character list. Use /showid again."}}) - end) - end - end - - -end \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/dispatchnotify/cl_dispatchnotify.lua b/resources/[sonorancad]/sonorancad/submodules/dispatchnotify/cl_dispatchnotify.lua deleted file mode 100644 index 072cd4d1f..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/dispatchnotify/cl_dispatchnotify.lua +++ /dev/null @@ -1,157 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: dispatchnotify - Creator: SonoranCAD - Description: Show incoming 911 calls and allow units to attach to them. - - Put all client-side logic in this file. -]] - -local trackingCall = false -local trackingID = nil - -CreateThread(function() Config.LoadPlugin("dispatchnotify", function(pluginConfig) - - if pluginConfig.enabled then - - local gpsLock = true - local lastPostal = nil - local lastCoords = nil - local currentCallId = nil - local lockedPlate = nil - local gpsBlip = false - - RegisterNetEvent("SonoranCAD::dispatchnotify:SetGps") - AddEventHandler("SonoranCAD::dispatchnotify:SetGps", function(postal) - -- try to set postal via command? - if gpsLock then - ExecuteCommand("postal "..tostring(postal)) - if lastPostal ~= nil and lastPostal ~= postal then - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Dispatch ^0] ", ("Call GPS coordinates updated (%s)."):format(postal)}}) - lastPostal = postal - else - lastPostal = postal - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Dispatch ^0] ", ("GPS coordinates set to caller's last known postal (%s)."):format(postal)}}) - end - end - end) - - RegisterNetEvent("SonoranCAD::dispatchnotify:UnsetGps") - AddEventHandler("SonoranCAD::dispatchnotify:UnsetGps", function() - if gpsBlip then - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Dispatch ^0] ", "You are now on scene. Disabling GPS."}}) - RemoveBlip(gpsBlip) - gpsBlip = nil - elseif lastPostal ~= nil then - ExecuteCommand("postal") - lastPostal = nil - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Dispatch ^0] ", "You are now on scene. Disabling GPS."}}) - end - end) - - RegisterNetEvent("SonoranCAD::dispatchnotify:SetLocation") - AddEventHandler("SonoranCAD::dispatchnotify:SetLocation", function(coords) - if coords == nil then - return warnLog("SetLocation was called, but no coordinates were found") - else - debugLog(("In SetLocation: x: %s y: %s z: %s"):format(coords.x, coords.y, coords.z)) - end - if gpsLock then - if gpsBlip then RemoveBlip(gpsBlip) end - gpsBlip = AddBlipForCoord(tonumber(coords.x), tonumber(coords.y), 0.0) - SetBlipRouteColour(gpsBlip, 3) - SetBlipRoute(gpsBlip, true) - if lastCoords ~= nil then - if lastCoords.x == coords.x and lastCoords.y == coords.y then - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Dispatch ^0] ", "GPS coordinates have been updated."}}) - return - end - end - lastCoords = coords - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Dispatch ^0] ", "GPS coordinates set to caller's last known location."}}) - end - end) - - RegisterNetEvent("SonoranCAD::dispatchnotify:BeginTracking") - AddEventHandler("SonoranCAD::dispatchnotify:BeginTracking", function(callID) - trackingCall = true - trackingID = callID - track() - end) - - RegisterNetEvent("SonoranCAD::dispatchnotify:StopTracking") - AddEventHandler("SonoranCAD::dispatchnotify:StopTracking", function() - trackingCall = false - trackingID = nil - end) - - RegisterCommand("togglegps", function(source, args, rawCommand) - gpsLock = not gpsLock - TriggerEvent("chat:addMessage", {args = {"^0[ ^2GPS ^0] ", ("GPS lock has been %s"):format(gpsLock and "enabled" or "disabled")}}) - end) - - RegisterNetEvent("SonoranCAD::dispatchnotify:CallAttach") - RegisterNetEvent("SonoranCAD::dispatchnotify:CallDetach") - RegisterNetEvent("SonoranCAD::dispatchnotify:AddNoteToCall") - - AddEventHandler("SonoranCAD::dispatchnotify:CallAttach", function(callId) - debugLog("Got attach for call "..tostring(callId)) - currentCallId = callId - end) - AddEventHandler("SonoranCAD::dispatchnotify:CallDetach", function(callId) - debugLog("Got detach for call "..tostring(callId)) - currentCallId = nil - if gpsBlip then RemoveBlip(gpsBlip) end - gpsBlip = nil - end) - - function track() - local lastpostal = nil - if trackingCall then - while trackingCall and trackingID ~= nil do - local postal = nil - if isPluginLoaded("postals") and getNearestPostal() ~= nil then - postal = getNearestPostal() - else - assert(false, "Required postal resource is not loaded. Cannot use postals plugin.") - end - if postal ~= nil and postal ~= lastpostal then - TriggerServerEvent("SonoranCAD::dispatchnotify:UpdateCallPostal", postal, trackingID) - lastpostal = postal - end - Citizen.Wait(pluginConfig.postalSendTimer) - end - end - end - - if pluginConfig.enableAddNote then - RegisterCommand(pluginConfig.addNoteCommand, function(source, args, rawCommand) - local note = table.concat(args, " ") - if currentCallId ~= nil then - TriggerServerEvent("SonoranCAD::dispatchnotify:AddNoteToCall", currentCallId, note) - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Note ^0] ", "Note sent to CAD."}}) - else - TriggerEvent("chat:addMessage", {args = {"^0[ ^4Error ^0] ", "Not attached to any call."}}) - end - end) - end - - if pluginConfig.enableAddPlate and isPluginLoaded("wraithv2") then - RegisterNetEvent("SonoranCAD::dispatchnotify:PlateLock") - AddEventHandler("SonoranCAD::dispatchnotify:PlateLock", function(plate) - debugLog("Got locked plate event "..tostring(plate)) - lockedPlate = plate - end) - RegisterCommand(pluginConfig.addPlateCommand, function(source, args, rawCommand) - if currentCallId ~= nil and lockedPlate ~= nil then - TriggerServerEvent("SonoranCAD::dispatchnotify:AddNoteToCall", currentCallId, ("PLATE NUMBER: %s"):format(lockedPlate)) - TriggerEvent("chat:addMessage", {args = {"^0[ ^2Note ^0] ", ("Locked plate %s sent to CAD."):format(lockedPlate)}}) - else - TriggerEvent("chat:addMessage", {args = {"^0[ ^4Error ^0] ", "Not attached to any call or no plate locked."}}) - end - end) - end - - end -end) end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/dispatchnotify/sv_dispatchnotify.lua b/resources/[sonorancad]/sonorancad/submodules/dispatchnotify/sv_dispatchnotify.lua deleted file mode 100644 index 806818466..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/dispatchnotify/sv_dispatchnotify.lua +++ /dev/null @@ -1,558 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: dispatchnotify - Creator: SonoranCAD - Description: Show incoming 911 calls and allow units to attach to them. - - Put all server-side logic in this file. -]] - -CreateThread(function() Config.LoadPlugin("dispatchnotify", function(pluginConfig) - -if pluginConfig.enabled then - - local DISPATCH_TYPE = {"CALL_NEW", "CALL_EDIT", "CALL_CLOSE", "CALL_NOTE", "CALL_SELF_CLEAR"} - local ORIGIN = {"CALLER", "RADIO_DISPATCH", "OBSERVED", "WALK_UP"} - local STATUS = {"PENDING", "ACTIVE", "CLOSED"} - - local CallOriginMapping = {} -- callId => playerId - local EmergencyToCallMapping = {} -- eCallId => CallId - local CallNotes = {} -- callid -> notes table - - local MappedCalls = {} -- eCallId -> call object - - local function findCall(id) - for idx, callId in pairs(EmergencyToCallMapping) do - debugLog(("check %s = %s"):format(id, callId)) - if id == callId then - return idx - end - end - return nil - end - - local function getCallFromOriginId(id) - for k, call in pairs(GetCallCache()) do - if call.dispatch ~= nil then - if call.dispatch.metaData ~= nil then - debugLog(("check %s = %s"):format(id, call.dispatch.metaData.createdFromId)) - if tonumber(call.dispatch.metaData.createdFromId) == tonumber(id) then - return call - end - end - end - end - return nil - end - - local function SendMessage(type, source, message) - debugLog(("Sending message to %s: %s"):format(source, message)) - if type == "dispatch" then - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^2Dispatch ^0] ", message}}) - elseif type == pluginConfig.emergencyCallType then - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^1"..type.." ^0] ", message}}) - elseif type == pluginConfig.civilCallType then - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^1"..type.." ^0] ", message}}) - elseif type == pluginConfig.dotCallType then - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^1"..type.." ^0] ", message}}) - elseif type == "error" then - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^1Error ^0] ", message}}) - elseif type == "debug" and Config.debugMode then - TriggerClientEvent("chat:addMessage", source, {args = {"[ Debug ] ", message}}) - end - end - - local function IsPlayerOnDuty(player) - if pluginConfig.unitDutyMethod == "incad" then - if GetUnitByPlayerId(tostring(player)) ~= nil then - return true - else - return false - end - elseif pluginConfig.unitDutyMethod == "permissions" then - return IsPlayerAceAllowed(player, "sonorancad.dispatchnotify") - elseif pluginConfig.unitDutyMethod == "esxjob" then - assert(isPluginLoaded("esxsupport") or isPluginLoaded("frameworksupport"), "frameworksupport plugin is required to use the esx/qb-core on duty method.") - local job = GetCurrentJob(player) - debugLog(("Player %s has job %s, return %s"):format(player, job, pluginConfig.esxJobsAllowed[GetCurrentJob(player)] )) - if pluginConfig.esxJobsAllowed[GetCurrentJob(player)] then - return true - else - return false - end - elseif pluginConfig.unitDutyMethod == "custom" then - return unitDutyCustom(player) - end - end - - local function addCallNote(callId, note) - if not CallNotes[callId] then - local tbl = {} - table.insert(tbl, note) - CallNotes[callId] = tbl - else - table.insert(CallNotes[callId], note) - end - end - - local function clearNotes(callId) - CallNotes[callId] = nil - end - - local ActiveDispatchers = {} - - AddEventHandler("SonoranCAD::pushevents:UnitLogin", function(unit) - if unit.isDispatch and pluginConfig.dispatchDisablesSelfResponse then - pluginConfig.enableUnitResponse = false - debugLog("Self dispatching disabled, dispatch is online") - table.insert(ActiveDispatchers, unit.id) - end - end) - - AddEventHandler("SonoranCAD::pushevents:UnitLogout", function(id) - local idx = nil - for i, k in pairs(ActiveDispatchers) do - if id == k then - idx = i - end - end - if idx ~= nil then - table.remove(ActiveDispatchers, idx) - end - if pluginConfig.dispatchDisablesSelfResponse and #ActiveDispatchers < 1 then - pluginConfig.enableUnitResponse = true - debugLog("Self dispatching enabled, dispatch is offline") - end - end) - - --EVENT_911 TriggerEvent('SonoranCAD::pushevents:IncomingCadCall', body.data.call, body.data.apiIds, body.data.metaData) - RegisterServerEvent("SonoranCAD::pushevents:IncomingCadCall") - AddEventHandler("SonoranCAD::pushevents:IncomingCadCall", function(call, metadata, apiIds) - if metadata ~= nil and metadata.callerPlayerId ~= nil then - CallOriginMapping[call.callId] = metadata.callerPlayerId - end - if pluginConfig.enableUnitNotify then - local type = call.emergency and pluginConfig.civilCallType or pluginConfig.emergencyCallType - local message = pluginConfig.incomingCallMessage:gsub("{caller}", call.caller):gsub("{location}", call.location):gsub("{description}", call.description):gsub("{callId}", call.callId):gsub("{command}", pluginConfig.respondCommandName) - for i = 0, GetNumPlayerIndices()-1 do - local player = GetPlayerFromIndex(i) - local unit = GetUnitByPlayerId(player) - if IsPlayerOnDuty(player) then - if pluginConfig.unitNotifyMethod == "chat" then - SendMessage(type, player, message) - elseif pluginConfig.unitNotifyMethod == "pnotify" then - TriggerClientEvent("pNotify:SendNotification", player, { - text = message, - type = "error", - layout = "bottomcenter", - timeout = "10000" - }) - elseif pluginConfig.unitNotifyMethod == "custom" then - TriggerClientEvent("SonoranCAD::dispatchnotify:IncomingCallNotify", player, message) - end - else - debugLog(("Ignore player %s, not on duty"):format(player)) - end - end - end - end) - - RegisterServerEvent("SonoranCAD::callcommands:EmergencyCallAdd") - AddEventHandler("SonoranCAD::callcommands:EmergencyCallAdd", function(playerId, callId) - CallOriginMapping[tonumber(callId)] = playerId - end) - - --Officer response - registerApiType("NEW_DISPATCH", "emergency") - registerApiType("ATTACH_UNIT", "emergency") - registerApiType("REMOVE_911", "emergency") - registerApiType("SET_CALL_POSTAL", "emergency") - RegisterCommand(pluginConfig.respondCommandName, function(source, args, rawCommand) - local source = tonumber(source) - local callId = args[1] - if callId == nil then - SendMessage("error", source, "Call ID must be specified.") - return - end - callId = tonumber(callId) - if not pluginConfig.enableUnitResponse then - SendMessage("error", source, "Self dispatching is disabled.") - return - end - if not IsPlayerOnDuty(source) then - SendMessage("error", source, "You must be on duty to use this command.") - return - end - if not GetUnitByPlayerId(source) then - SendMessage("error", source, "Due to system limitations, you must be logged into the CAD to self attach.") - return - end - - -- Fetch if call hasn't been responded to yet - local call = GetEmergencyCache()[callId] - if call == nil then - -- Call responded, grab from mapping - call = MappedCalls[callId] - end - if call == nil then - -- not in mapping, check call cache - call = getCallFromOriginId(callId) - end - if call == nil then - SendMessage("error", source, "Could not find that call ID") - return - elseif call.dispatch ~= nil then - call = call.dispatch - end - local callerPlayerId = nil - local originCall = nil - if call.metaData ~= nil then - callerPlayerId = call.metaData.callerPlayerId - originCall = call.metaData.createdFromId - end - if call.metaData ~= nil and callerPlayerId == nil then - debugLog("failed to find caller info") - end - local identifiers = GetIdentifiers(source)[Config.primaryIdentifier] - if originCall == nil then - -- no mapped call, create a new one - debugLog(("Creating new call request...(no mapped call for %s)"):format(callId)) - local postal = "" - if isPluginLoaded("postals") and callerPlayerId ~= nil then - if PostalsCache[tonumber(callerPlayerId)] ~= nil then - postal = PostalsCache[tonumber(callerPlayerId)] - else - debugLog("Failed to obtain postal. "..json.encode(PostalsCache)) - return - end - end - if call.metaData ~= nil and call.metaData.useCallLocation == "true" and call.metaData.callPostal ~= nil then - postal = call.metaData.callPostal - end - local title = "OFFICER RESPONSE - "..call.callId - if pluginConfig.callTitle ~= nil then - title = pluginConfig.callTitle.." - "..call.callId - end - metaData = {callerPlayerId = callerPlayerId, createdFromId = call.callId } - if call.metaData ~= nil then - for k, v in pairs(call.metaData) do - metaData[k] = v - end - end - if LocationCache[source] ~= nil and metaData['x'] == nil then - metaData['x'] = LocationCache[source].coordinates.x - metaData['y'] = LocationCache[source].coordinates.y - metaData['z'] = LocationCache[source].coordinates.z - end - local payload = { serverId = Config.serverId, - origin = 0, - status = 1, - priority = 2, - block = "", - code = "", - postal = (postal ~= nil and postal or ""), - address = (call.location ~= nil and call.location or "Unknown"), - title = title, - description = (call.description ~= nil and call.description or ""), - isEmergency = call.isEmergency, - notes = { - {time = '00:00:00', label = 'Dispatch', type = 'text', content = 'Officer Responding'} - }, - metaData = metaData, - units = { identifiers } - } - performApiRequest({payload}, "NEW_DISPATCH", function(response) - debugLog("Call creation OK") - if response:match("NEW DISPATCH CREATED - ID:") then - TriggerEvent("SonoranCAD::dispatchnotify:UnitRespond", source, response:match("%d+")) - EmergencyToCallMapping[call.callId] = tonumber(response:match("%d+")) - end - -- remove the 911 call - local payload = { serverId = Config.serverId, callId = call.callId } - performApiRequest({payload}, "REMOVE_911", function(resp) - debugLog("Remove status: "..tostring(resp)) - end) - end) - else - -- Call already exists - debugLog("Found Call. Attaching!") - local data = {callId = call.callId, units = {identifiers}, serverId = Config.serverId} - performApiRequest({data}, "ATTACH_UNIT", function(res) - debugLog("Attach OK: "..tostring(res)) - SendMessage("debug", source, "You have been attached to the call.") - end) - end - end) - - RegisterNetEvent("SonoranCAD::dispatchnotify:CallAttach") - RegisterNetEvent("SonoranCAD::dispatchnotify:CallDetach") - RegisterServerEvent("SonoranCAD::pushevents:UnitAttach") - AddEventHandler("SonoranCAD::pushevents:UnitAttach", function(call, unit) - debugLog("hello, unit attach! "..json.encode(call)) - local callerId = nil - if call.dispatch.metaData ~= nil and call.dispatch.metaData.callerPlayerId ~= nil then - debugLog("set caller ID "..call.dispatch.metaData.callerPlayerId) - callerId = call.dispatch.metaData.callerPlayerId - end - local officerId = GetSourceByApiId(unit.data.apiIds) - if officerId ~= nil then - SendMessage("dispatch", officerId, ("You are now attached to call ^4%s^0. Description: ^4%s^0"):format(call.dispatch.callId, call.dispatch.description)) - TriggerClientEvent("SonoranCAD::dispatchnotify:CallAttach", officerId, call.dispatch.callId) - local callerLocation = nil - if callerId ~= nil then - callerLocation = findPlayerLocation(callerId) - end - if callerLocation == nil or call.dispatch.metaData.useCallLocation then - callerLocation = {x=call.dispatch.metaData.x, y=call.dispatch.metaData.y, z=call.dispatch.metaData.z} - end - debugLog(("Sending location data %s to %s (call data: %s)"):format(json.encode(callerLocation), officerId, json.encode(call))) - if pluginConfig.waypointType == "exact" and callerLocation ~= nil then - TriggerClientEvent("SonoranCAD::dispatchnotify:SetLocation", officerId, callerLocation) - elseif pluginConfig.waypointType == "postal" or pluginConfig.waypointFallbackEnabled then - if call.dispatch.postal ~= nil and call.dispatch.postal ~= "" then - TriggerClientEvent("SonoranCAD::dispatchnotify:SetGps", officerId, call.dispatch.postal) - if call.dispatch.metaData ~= nil and call.dispatch.metaData.trackPrimary == "True" then - if GetSourceByApiId(GetUnitCache()[call.dispatch.idents[1]].data.apiIds) == officerId then - TriggerClientEvent("SonoranCAD::dispatchnotify:BeginTracking", officerId, call.dispatch.callId) - end - end - end - else - local lc = LocationCache[callerId] - if lc == nil then - lc = { ['error'] = "locationcache is nil"} - end - debugLog(("LOCATION SETTING: Failed to send client location. - waypointType: %s - callerId: %s - LocationCache: %s"):format(pluginConfig.waypointType, callerId, json.encode(lc))) - end - else - debugLog("failed to find unit "..json.encode(unit)) - end - if pluginConfig.enableCallerNotify and callerId ~= nil and call.dispatch.metaData.silentAlert == "false" then - if pluginConfig.callerNotifyMethod == "chat" then - SendMessage("dispatch", callerId, pluginConfig.notifyMessage:gsub("{officer}", unit.data.name)) - elseif pluginConfig.callerNotifyMethod == "pnotify" then - TriggerClientEvent("pNotify:SendNotification", callerId, { - text = pluginConfig.notifyMessage:gsub("{officer}", unit.data.name), - type = "error", - layout = "bottomcenter", - timeout = "10000" - }) - elseif pluginConfig.callerNotifyMethod == "custom" then - TriggerEvent("SonoranCAD::dispatchnotify:UnitAttach", call.dispatch, callerId, officerId, unit.data.name) - end - else - debugLog(("pluginConfig.enableCallerNotify == %s and %s ~= nil and not %s == 'false'"):format(pluginConfig.enableCallerNotify, callerId, call.dispatch.metaData.silentAlert)) - end - end) - - RegisterServerEvent("SonoranCAD::pushevents:DispatchEvent") - AddEventHandler("SonoranCAD::pushevents:DispatchEvent", function(data) - local dispatchType = data.dispatch_type - local dispatchData = data.dispatch - local metaData = data.dispatch.metaData - if dispatchType ~= tostring(dispatchType) then - -- hmm, expected a string, got a number - dispatchType = DISPATCH_TYPE[data.dispatch_type+1] - end - local switch = { - ["CALL_NEW"] = function() - debugLog("CALL_NEW fired "..json.encode(dispatchData)) - local emergencyId = dispatchData.metaData.createdFromId - for k, id in pairs(dispatchData.idents) do - local unit = GetUnitCache()[GetUnitById(id)] - if not unit then - debugLog("Not sending attach, unit not online") - else - local officerId = GetSourceByApiId(unit.data.apiIds) - TriggerEvent("SonoranCAD::pushevents:UnitAttach", data, unit) - end - end - end, - ["CALL_CLOSE"] = function() - debugLog("CALL_CLOSE fired "..json.encode(dispatchData)) - if dispatchData == nil or dispatchData.dispatch == nil then - debugLog("nil value detected, ignore it") - return - end - local cache = GetCallCache()[dispatchData.dispatch.callId] - if cache.units ~= nil then - for k, v in pairs(cache.units) do - local officerId = GetUnitCache()[GetUnitById(v.id)] - if officerId ~= nil then - TriggerClientEvent("SonoranCAD::dispatchnotify:CallClosed", officerId, cache.callId) - end - end - end - clearNotes(dispatchData.dispatch.callId) - end, - ["CALL_NOTE"] = function() - TriggerEvent("SonoranCAD::dispatchnotify:CallNote", dispatchData.callId, dispatchData.notes) - end, - ["CALL_SELF_CLEAR"] = function() - TriggerEvent("SonoranCAD::dispatchnotify:CallSelfClear", dispatchData.units) - end - } - if switch[dispatchType] then - switch[dispatchType]() - end - end) - - AddEventHandler("SonoranCAD::pushevents:DispatchEdit", function(before, after) - if before.dispatch.primary ~= after.dispatch.primary then - -- Primary Unit Updated, remove tracking from old unit. - local unit = GetUnitCache()[GetUnitById(before.dispatch.primary)] - if unit ~= nil then - local officerId = GetSourceByApiId(unit.data.apiIds) - TriggerClientEvent("SonoranCAD::dispatchnotify:StopTracking", officerId) - end - end - if before.dispatch.primary ~= after.dispatch.primary or before.dispatch.trackPrimary ~= after.dispatch.trackPrimary then - TriggerEvent("SonoranCAD::dispatchnotify:CallEdit:Tracking", after.dispatch.callId, after.dispatch.trackPrimary, after.dispatch.primary) - end - if before.dispatch.postal ~= after.dispatch.postal then - TriggerEvent("SonoranCAD::dispatchnotify:CallEdit:Postal", after.dispatch.callId, after.dispatch.postal) - end - if before.address ~= after.address then - TriggerEvent("SonoranCAD::dispatchnotify:CallEdit:Address", after.dispatch.callId, after.dispatch.address) - end - end) - - AddEventHandler("SonoranCAD::dispatchnotify:CallEdit:Tracking", function(callId, tracking, primary) - local call = GetCallCache()[callId] - assert(call ~= nil, "Call not found, failed to process.") - local unit = GetUnitCache()[GetUnitById(primary)] - local officerId = GetSourceByApiId(unit.data.apiIds) - if tracking then - TriggerClientEvent("SonoranCAD::dispatchnotify:BeginTracking", officerId, callId) - else - TriggerClientEvent("SonoranCAD::dispatchnotify:StopTracking", officerId) - end - end) - - - AddEventHandler("SonoranCAD::pushevents:UnitDetach", function(call, unit) - local officerId = GetSourceByApiId(unit.data.apiIds) - if GetCallCache()[call.dispatch.callId] == nil then - debugLog("Ignore unit detach, call doesn't exist") - return - end - if officerId ~= nil and call ~= nil and call.dispatch.metaData ~= nil then - if call.dispatch.metaData.trackPrimary then - TriggerClientEvent("SonoranCAD::dispatchnotify:StopTracking", officerId) - end - TriggerClientEvent("SonoranCAD::dispatchnotify:CallDetach", officerId, call.dispatch.callId) - SendMessage("dispatch", officerId, ("You were detached from call %s."):format(call.dispatch.callId)) - end - end) - - AddEventHandler("SonoranCAD::dispatchnotify:CallEdit:Postal", function(callId, postal) - local call = GetCallCache()[callId] - assert(call ~= nil, "Call not found, failed to process.") - if call.dispatch.idents == nil then - debugLog("no units attached "..json.encode(call)) - return - end - for k, id in pairs(call.dispatch.idents) do - local unit = GetUnitCache()[GetUnitById(id)] - if unit == nil then - debugLog(("Unit was nil, requested %s, cache is: %s"):format(id, GetUnitCache())) - return - end - local officerId = GetSourceByApiId(unit.data.apiIds) - if officerId ~= nil then - TriggerClientEvent("SonoranCAD::dispatchnotify:SetGps", officerId, postal) - else - debugLog("couldn't find officer") - end - end - end) - RegisterServerEvent("SonoranCAD::dispatchnotify:UpdateCallPostal") - AddEventHandler("SonoranCAD::dispatchnotify:UpdateCallPostal", function(clpostal, callid) - local data = {} - data[1] = { - callId = callid, - postal = clpostal, - serverId = Config.serverId - } - performApiRequest(data, 'SET_CALL_POSTAL', function() end) - end) - - AddEventHandler("SonoranCAD::pushevents:DispatchNote", function(call, data) - if not pluginConfig.sendNotesToUnits then - return - end - if not call then - debugLog(("Failed to find call: %s"):format(json.encode(data))) - return - end - call = call.dispatch - -- add note to cache - addCallNote(data.callId, data.note) - debugLog(("Incoming note for ID %s, call: %s"):format(data.callId, json.encode(call))) - local noteContent = type(data.note) == 'table' and data.note.content or data.note - if call.idents ~= nil and type(noteContent) == 'string' then - for _, ident in pairs(call.idents) do - local officerId = GetUnitCache()[GetUnitById(ident)] - if officerId ~= nil then - local patterns = { ["{callid}"] = data.callId, ["{note}"] = noteContent} - local message = pluginConfig.noteMessage - for k, v in pairs(patterns) do - message = message:gsub(k, v) - end - if pluginConfig.noteNotifyMethod == "chat" then - SendMessage("dispatch", officerId, message) - elseif pluginConfig.noteNotifyMethod == "pnotify" then - TriggerClientEvent("pNotify:SendNotification", officerId, { - text = message, - type = "info", - layout = "bottomcenter", - timeout = "10000" - }) - else - TriggerClientEvent("SonoranCAD::dispatchnotify:NewCallNote", officerId, data) - end - else - debugLog(("Skipping officer %s, not available"):format(ident)) - end - end - end - end) - - registerApiType("ADD_CALL_NOTE", "emergency") - RegisterNetEvent("SonoranCAD::dispatchnotify:AddNoteToCall") - AddEventHandler("SonoranCAD::dispatchnotify:AddNoteToCall", function(callId, note) - local source = source - debugLog(("Got note add request from %s, call id %s: %s"):format(source, callId, note)) - local call = GetCallCache()[callId] - if call == nil then - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^2Dispatch ^0] ", "Unable to find call."}}) - else - local payload = { serverId = Config.serverId, note = note, callId = callId } - performApiRequest({payload}, "ADD_CALL_NOTE", function(res) end) - end - end) - if isPluginLoaded("wraithv2") then - AddEventHandler("wk:onPlateLocked", function(cam, plate, index) - local plate = plate:match("^%s*(.-)%s*$") - if IsPlayerOnDuty(source) then - TriggerClientEvent("SonoranCAD::dispatchnotify:PlateLock", source, plate) - end - end) - else - debugLog("Not loading radar lock as wraith plugin is not loaded") - end - - AddEventHandler("SonoranCAD::pushevents:UnitUpdate", function(unit, status) - local u = GetUnitCache()[unit] - if u then - local player = GetSourceByApiId(u.data.apiIds) - if player then - TriggerClientEvent("SonoranCAD::dispatchnotify:UnsetGps", player) - end - end - end) - -end - -end) end) diff --git a/resources/[sonorancad]/sonorancad/submodules/fivepd/cl_fivepd.lua b/resources/[sonorancad]/sonorancad/submodules/fivepd/cl_fivepd.lua deleted file mode 100644 index 10e649907..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/fivepd/cl_fivepd.lua +++ /dev/null @@ -1,17 +0,0 @@ ---[[ - Sonaran CAD Plugins - Plugin Name: fivepd - Creator: SonoranCAD - Description: Callouts and Record Sync with FivePD -]] - -CreateThread(function() - Config.LoadPlugin("fivepd", function(pluginConfig) - - if pluginConfig.enabled then - - - end - - end) -end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/fivepd/put_in_fivepd_plugins/SonoranPlugin.net.dll b/resources/[sonorancad]/sonorancad/submodules/fivepd/put_in_fivepd_plugins/SonoranPlugin.net.dll deleted file mode 100644 index c0e230e71..000000000 Binary files a/resources/[sonorancad]/sonorancad/submodules/fivepd/put_in_fivepd_plugins/SonoranPlugin.net.dll and /dev/null differ diff --git a/resources/[sonorancad]/sonorancad/submodules/fivepd/sv_fivepd.lua b/resources/[sonorancad]/sonorancad/submodules/fivepd/sv_fivepd.lua deleted file mode 100644 index b5faaf9e2..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/fivepd/sv_fivepd.lua +++ /dev/null @@ -1,73 +0,0 @@ ---[[ - Sonaran CAD Plugins - Plugin Name: fivepd - Creator: SonoranCAD - Description: Callouts and Record Sync with FivePD -]] - -CreateThread(function() - Config.LoadPlugin("fivepd", function(pluginConfig) - if pluginConfig.enabled then - local postalsConfig = Config.GetPluginConfig('postals') - registerApiType("NEW_DISPATCH", "emergency") - - -- New Callout Handler - function CreateNewCallout(src, callName, callDesc, callResponse, callLocation, callCoord) - local identifier = GetIdentifiers(src)[Config.primaryIdentifier] - local units = {identifier} - local notes = "" - local postal = "" - if postalsConfig and postalsConfig.enabled then - postal = getPostalFromVector3(callCoord) or "" - end - - local data = { - ['serverId'] = Config.serverId, - ['origin'] = pluginConfig.origin, - ['status'] = pluginConfig.status, - ['priority'] = callResponse, - ['block'] = "", -- not used, but required - ['postal'] = postal, - ['address'] = callLocation ~= nil and callLocation or 'Unknown', - ['title'] = callName, - ['code'] = pluginConfig.code, -- TODO - ['description'] = callDesc, - ['units'] = units, - ['notes'] = {} -- required but empty - } - - debugLog("Sending New Callout") - performApiRequest({data}, 'NEW_DISPATCH', function() end) - end - - RegisterServerEvent("SonoranCAD::fivepd:CalloutReceived", function(src, callIdent, callId, callName, callDesc, callResponse, callLocX, callLocY, callLocZ) - -- This Event doesn't seem to trigger so I didn't use it. - end) - RegisterServerEvent("SonoranCAD::fivepd:CalloutAccepted", function(src, callIdent, callId, callName, callDesc, callResponse, callLocation, callCoord) - CreateNewCallout(src, callName, callDesc, callResponse, callLocation, callCoord) - end) - RegisterServerEvent("SonoranCAD::fivepd:CalloutCompleted", function(src, callIdent, callId, callName, callDesc, callResponse, callLocX, callLocY, callLocZ) - print(src .. " completed callout: " .. json.encode(callout)) - - end) - RegisterServerEvent("SonoranCAD::fivepd:DutyStatusChange", function(src, onDuty) - print(src .. " is on duty: " .. tostring(onDuty)) - - end) - RegisterServerEvent("SonoranCAD::fivepd:ServiceCalled", function(src, service) - print(src .. " called for: " .. tostring(service)) - - end) - RegisterServerEvent("SonoranCAD::fivepd:RankChanged", function(src, rank) - print(src .. " is now rank: " .. tostring(rank)) - - end) - RegisterServerEvent("SonoranCAD::fivepd:PedArrested", function(src, pedData) - print(src .. " arrested ped: " .. tostring(pedData.FirstName) .. " " .. tostring(pedData.LastName)) - - end) - - end - - end) -end) diff --git a/resources/[sonorancad]/sonorancad/submodules/forcereg/cl_forcereg.lua b/resources/[sonorancad]/sonorancad/submodules/forcereg/cl_forcereg.lua deleted file mode 100644 index 76ab52c58..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/forcereg/cl_forcereg.lua +++ /dev/null @@ -1,139 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: forcereg - Creator: Era#1337 - Description: Requires players to link their API IDs to a valid Sonoran account. - -]] - -local pluginConfig = Config.GetPluginConfig("forcereg") - -if pluginConfig.enabled then - - local isNagging = false - local isFreezing = false - local freezePos = nil - local isNoSpawn = false - local id = nil - local idString = nil - - RegisterNetEvent("SonoranCAD::forcereg:PlayerReg") - AddEventHandler("SonoranCAD::forcereg:PlayerReg", function(identifier, exists) - if not exists then - Wait(1) - id = identifier - idString = identifier - if isPluginLoaded("esxsupport") then - if Config.plugins.esxsupport.usePrefix then - idString = ("%s:%s"):format(Config.primaryIdentifier, identifier) - else - idString = identifier - end - end - print(("Identifier %s does not exist."):format(idString)) - if pluginConfig.captiveOption:lower() == "nag" then - isNagging = true - elseif pluginConfig.captiveOption:lower() == "freeze" then - isFreezing = true - elseif pluginConfig.captiveOption:lower() == "nospawn" then - isNoSpawn = true - else - assert(false, 'Invalid captiveOption!') - end - else - print("Identity verified.") - isNagging = false - isFreezing = false - freezePos = nil - isNoSpawn = false - end - end) - - TriggerServerEvent("SonoranCAD::forcereg:CheckPlayer") - - RegisterCommand("verifycad", function(source, args, rawCommand) - TriggerServerEvent("SonoranCAD::forcereg:CheckPlayer") - end) - - CreateThread(function() - while true do - if isNagging then - -- USER CONFIG: Change the below to adjust the text to your liking - if pluginConfig.nagDrawTextLocation:lower() == "top" then - DrawText2D(pluginConfig.captiveMessage, 0, 0, 0.305, 0.01, 0.3, 255, 255, 255, 150) - DrawText2D(pluginConfig.instructionalMessage, 0, 0, 0.3, 0.03, 0.3, 255, 255, 255, 150) - DrawText2D(pluginConfig.verifyMessage.." API ID: ~r~"..id, 0, 0, 0.35, 0.06, 0.3, 255, 255, 255, 150) - elseif pluginConfig.nagDrawTextLocation:lower() == "center" then - DrawText2D(pluginConfig.captiveMessage, 0, 0, 0.2, 0.4, 0.5, 255, 255, 255, 150) - DrawText2D(pluginConfig.instructionalMessage, 0, 0, 0.195, 0.45, 0.5, 255, 255, 255, 150) - DrawText2D(pluginConfig.verifyMessage.." API ID: ~r~"..idString, 0, 0, 0.265, 0.5, 0.5, 255, 255, 255, 150) - end - -- END USER CONFIG - Wait(0) - elseif isFreezing then - CreateThread(function() - while isFreezing do - if freezePos == nil then - freezePos = GetEntityCoords(PlayerPedId()) - end - FreezeEntityPosition(PlayerPedId(), true) - ClearPedTasksImmediately(PlayerPedId()) - SetEntityCoords(PlayerPedId(), freezePos, 0.0, 0.0, 0.0, false) - - -- USER CONFIG: Change the below to adjust the text to your liking - DrawText2D(pluginConfig.captiveMessage, 0, 0, 0.2, 0.4, 0.5, 255, 255, 255, 150) - DrawText2D(pluginConfig.instructionalMessage, 0, 0, 0.195, 0.45, 0.5, 255, 255, 255, 150) - DrawText2D(pluginConfig.verifyMessage.." API ID: ~r~"..idString, 0, 0, 0.265, 0.5, 0.5, 255, 255, 255, 150) - -- END USER CONFIG - Wait(0) - end - FreezeEntityPosition(PlayerPedId(), false) - freezePos = nil - end) - Wait(1000) - while freezePos ~= nil do - Wait(10) - end - - elseif isNoSpawn then - -- do nothing, for now - else - Wait(100) - end - end - end) - -end - - --- utility - -local AspectRatio -local ScreenWidth -local ScreenHeight - -Citizen.CreateThread(function() - AspectRatio = GetAspectRatio(false) - ScreenWidth = 1080 * AspectRatio - ScreenHeight = 1080 -end) - -function DrawText2D(text, font, centre, px, py, scale, r, g, b, a, labelGen) - if labelGen then - AddTextEntry(labelGen, text) - end - SetTextFont(font) - SetTextProportional(0) - SetTextScale(scale, scale) - SetTextColour(r or 255, g or 255, b or 255, a or 255) - SetTextDropShadow(0, 0, 0, 0,255) - SetTextEdge(1, 0, 0, 0, 255) - --SetTextOutline() - SetTextCentre(centre) - SetTextEntry(labelGen or "STRING") - AddTextComponentString(text) - local x = px + (scale / 2.0) / ScreenWidth - local y = py + (scale / 2.0) / ScreenHeight - DrawText(x, y) -end diff --git a/resources/[sonorancad]/sonorancad/submodules/forcereg/sv_forcereg.lua b/resources/[sonorancad]/sonorancad/submodules/forcereg/sv_forcereg.lua deleted file mode 100644 index 906fce3fa..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/forcereg/sv_forcereg.lua +++ /dev/null @@ -1,103 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: forcereg - Creator: Era#1337 - Description: Requires players to link their API IDs to a valid Sonoran account. - -]] - -local pluginConfig = Config.GetPluginConfig("forcereg") - -if pluginConfig.enabled then - - if pluginConfig.captiveOption == "whitelist" then - local function checkApiId(apiId, deferral, cb) - cadApiIdExists(apiId, function(exists) - debugLog(("checkApiId %s"):format(exists)) - cb(exists, deferral) - end) - end - - AddEventHandler("playerConnecting", function(name, setMessage, deferrals) - local source = source - deferrals.defer() - Wait(1) - deferrals.update("Checking CAD account, please wait...") - checkApiId(GetIdentifiers(source)[Config.primaryIdentifier], deferrals, function(exists, deferral) - print("exists: "..tostring(exists)) - if not exists then - deferral.done(pluginConfig.captiveMessage) - else - deferral.done() - end - end) - end) - end - - - - RegisterNetEvent("SonoranCAD::forcereg:CheckPlayer") - AddEventHandler("SonoranCAD::forcereg:CheckPlayer", function() - TriggerEvent("SonoranCAD::apicheck:CheckPlayerLinked", source) - end) - - AddEventHandler("SonoranCAD::apicheck:CheckPlayerLinkedResponse", function(player, identifier, exists) - if not pluginConfig.whitelist then - pluginConfig.whitelist = { - enabled = false, - mode = "qb-core", -- qb-core, esx, ace - aces = { -- ace permissions will see the message - "forcereg.whitelist" - }, - jobs = { -- QB or ESX jobs will see the message - "police" - } - } - print("Forcereg: Whitelist configuration not found, using defaults. Please update your configuration.") - end - if pluginConfig.whitelist.enabled then - if pluginConfig.whitelist.mode == "ace" then - local aceAllowed = false - for i=1, #pluginConfig.whitelist.aces do - if IsPlayerAceAllowed(player, pluginConfig.whitelist.aces[i]) then - aceAllowed = true - break - end - end - if aceAllowed then - TriggerClientEvent("SonoranCAD::forcereg:PlayerReg", player, identifier, exists) - end - elseif pluginConfig.whitelist.mode == "qb-core" then - local QBCore = exports['qb-core']:GetCoreObject() - local Player = QBCore.Functions.GetPlayer(player) - local job = Player.PlayerData.job.name - if job ~= nil then - for i=1, #pluginConfig.whitelist.jobs do - if job == pluginConfig.whitelist.jobs[i] then - TriggerClientEvent("SonoranCAD::forcereg:PlayerReg", player, identifier, exists) - break - end - end - end - elseif pluginConfig.whitelist.mode == "esx" then - local ESX = exports['es_extended']:getSharedObject() - local xPlayer = ESX.GetPlayerFromId(player) - local job = xPlayer.job.name - if job ~= nil then - for i=1, #pluginConfig.whitelist.jobs do - if job == pluginConfig.whitelist.jobs[i] then - TriggerClientEvent("SonoranCAD::forcereg:PlayerReg", player, identifier, exists) - break - end - end - end - end - else - TriggerClientEvent("SonoranCAD::forcereg:PlayerReg", player, identifier, exists) - end - end) - - - -end \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/frameworksupport/cl_frameworksupport.lua b/resources/[sonorancad]/sonorancad/submodules/frameworksupport/cl_frameworksupport.lua deleted file mode 100644 index a6a9db3f0..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/frameworksupport/cl_frameworksupport.lua +++ /dev/null @@ -1,108 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: frameworksupport - Creator: Sonoran Software Systems LLC - Description: Enable using ESX or QBCore character information in Sonoran integration plugins -]] CreateThread(function() - Config.LoadPlugin('frameworksupport', function(pluginConfig) - - if pluginConfig.enabled then - CreateThread(function() - local QBCore = nil - if pluginConfig.usingQBCore then - QBCore = exports['qb-core']:GetCoreObject() - end - PlayerData = {} - local ESX = nil - - CreateThread(function() - if not pluginConfig.usingQBCore then - ESX = exports['es_extended']:getSharedObject() - end - if pluginConfig.usingQBCore then - while QBCore.Functions.GetPlayerData() == nil do - Wait(10) - end - PlayerData = QBCore.Functions.GetPlayerData() - else - while ESX.GetPlayerData() == nil do - Wait(10) - end - PlayerData = ESX.GetPlayerData() - end - end) - - -- Listen for when new players load into the game - RegisterNetEvent('esx:playerLoaded') - AddEventHandler('esx:playerLoaded', function(xPlayer) - if pluginConfig.usingQBCore then - PlayerData = QBCore.Functions.GetPlayerData() - else - PlayerData = xPlayer - end - end) - -- Listen for when jobs are changed in esx_jobs - if pluginConfig.usingQBCore then - RegisterNetEvent('QBCore:Client:OnJobUpdate') - AddEventHandler('QBCore:Client:OnJobUpdate', function(job) - PlayerData.job = job - if PlayerData.job.onduty == true then - PlayerData.job.name = 'offduty' .. PlayerData.job.name - end - TriggerServerEvent('SonoranCAD::frameworksupport:refreshJobCache') - TriggerEvent('SonoranCAD::frameworksupport:JobUpdate', job) - end) - else - RegisterNetEvent('esx:setJob') - AddEventHandler('esx:setJob', function(job) - PlayerData.job = job - TriggerServerEvent('SonoranCAD::frameworksupport:refreshJobCache') - TriggerEvent('SonoranCAD::frameworksupport:JobUpdate', job) - end) - end - -- QBUS onduty change (ESX typically uses jobs to change duty instead) - if pluginConfig.usingQBCore then - RegisterNetEvent('QBCore:Client:SetDuty') - AddEventHandler('QBCore:Client:SetDuty', function(onduty) - local job = PlayerData.job - if onduty then - job.name = string.gsub(job.name, 'offduty', '') - else - job.name = 'offduty' .. job.name - end - PlayerData.job = job - TriggerServerEvent('SonoranCAD::frameworksupport:refreshJobCache') - TriggerEvent('SonoranCAD::frameworksupport:JobUpdate', job) - end) - end - - -- Function to return esx_identity data on the client from server - -- This event listens for data from the server when requested - local recievedIdentity = false - returnedIdentity = nil - RegisterNetEvent('SonoranCAD::frameworksupport:returnIdentity') - AddEventHandler('SonoranCAD::frameworksupport:returnIdentity', function(data) - recievedIdentity = true - if data.job == nil then - warnLog('Warning: no identity data was found.') - else - returnedIdentity = data - end - end) - -- This function requests data from the server - function GetIdentity(callback) - recievedIdentity = false - returnIdentity = false - TriggerServerEvent('SonoranCAD::frameworksupport:getIdentity') - local timeStamp = GetGameTimer() - while not recievedIdentity do - Wait(0) - end - callback(returnedIdentity) - end - - end) - end - end) -end) diff --git a/resources/[sonorancad]/sonorancad/submodules/frameworksupport/sv_frameworksupport.lua b/resources/[sonorancad]/sonorancad/submodules/frameworksupport/sv_frameworksupport.lua deleted file mode 100644 index b36689816..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/frameworksupport/sv_frameworksupport.lua +++ /dev/null @@ -1,368 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: frameworksupport - Creator: Sonoran Software Systems LLC - Description: Enable using ESX (or ESX clones) character information in Sonoran integration plugins -]] CreateThread(function() - Config.LoadPlugin('frameworksupport', function(pluginConfig) - - if pluginConfig.enabled then - - if GetResourceState('qb-core') ~= "started" and GetResourceState('es_extended') ~= 'started' then - errorLog('Both qb-core and es_extended are not started. Disabling framework support.') - pluginConfig.enabled = false - pluginConfig.disableReason = 'qb-core and es_extended not started' - return - end - local QBCore = nil - local ESX = nil - if pluginConfig.usingQBCore then - if GetResourceState('qb-core') ~= "started" then - errorLog('qb-core is not started. Disabling framework support.') - pluginConfig.enabled = false - pluginConfig.disableReason = 'qb-core not started' - return - end - QBCore = exports['qb-core']:GetCoreObject() - end - if not pluginConfig.usingQBCore then - if GetResourceState('es_extended') ~= 'started' then - errorLog('es_extended is not started. Disabling framework support.') - pluginConfig.enabled = false - pluginConfig.disableReason = 'es_extended not started' - return - end - ESX = exports['es_extended']:getSharedObject() - end - JobCache = {} - - RegisterNetEvent('QBCore:Client:OnPlayerLoaded') - AddEventHandler('QBCore:Client:OnPlayerLoaded', function() - playerName = QBCore.Functions.GetPlayerData() - end) - - -- Legacy ESX helper functions to get Character Info using MySQL-Async - local function safeParameters(params) - if nil == params then - return {[''] = ''} - end - - assert(type(params) == 'table', 'A table is expected') - assert(params[1] == nil, 'Parameters should not be an array, but a map (key / value pair) instead') - - if next(params) == nil then - return {[''] = ''} - end - - return params - end - - function MysqlAsyncFetchAll(query, params, func) - assert(type(query) == 'string', 'The SQL Query must be a string') - - exports['mysql-async']:mysql_fetch_all(query, safeParameters(params), func) - end - - function MysqlSyncFetchAll(query, params) - assert(type(query) == 'string', 'The SQL Query must be a string') - - local res = {} - local finishedQuery = false - exports['mysql-async']:mysql_fetch_all(query, safeParameters(params), function(result) - res = result - finishedQuery = true - end) - repeat - Wait(0) - until finishedQuery == true - return res - end - - function GetLegacyCharInfo(target, callback) - local identifier = GetPlayerIdentifiers(target)[1] - local result = MysqlSyncFetchAll('SELECT * FROM `users` WHERE `identifier` = @identifier', {['@identifier'] = identifier}) - if result[1]['firstname'] ~= nil then - local data = {identifier = result[1]['identifier'], firstname = result[1]['firstname'], lastname = result[1]['lastname'], dateofbirth = result[1]['dateofbirth'], sex = result[1]['sex'], - height = result[1]['height']} - callback(data) - else - local data = {identifier = identifier, firstname = '', lastname = '', dateofbirth = '', sex = '', height = ''} - callback(data) - end - end - - -- Helper function to get the ESX Identity object from your database/framework - function GetIdentity(target, cb) - local xPlayer = nil - if pluginConfig.usingQBCore then - xPlayer = QBCore.Functions.GetPlayer(target) - else - xPlayer = ESX.GetPlayerFromId(target) - end - if xPlayer ~= nil then - debugLog('GetIdentity OK') - if pluginConfig.usingQBCore then - xPlayer.firstName = xPlayer.PlayerData.charinfo.firstname - xPlayer.lastName = xPlayer.PlayerData.charinfo.lastname - xPlayer.name = xPlayer.firstName .. ' ' .. xPlayer.lastName - elseif pluginConfig.legacyESX then - -- Get Char info from Database using MySQL-Async - GetLegacyCharInfo(target, function(data) - -- debug logging for lookups that find no user data in database - if data.firstname == '' then - debugLog('Legacy ESX database lookup found no user data for identifier: ' .. tostring(data.identifier)) - end - -- Set quick reference variables - xPlayer.firstname = data.firstname - xPlayer.lastName = data.lastname - xPlayer.name = data.firstname .. ' ' .. data.lastname - -- Adjust xPlayer.getName() - xPlayer.getName = function() - return xPlayer.name - end - end) - end - if cb ~= nil then - debugLog('Running callback') - cb(xPlayer) - else - debugLog('Running client event') - TriggerClientEvent('SonoranCAD::frameworksupport:returnIdentity', target, xPlayer) - end - else - debugLog('GetIdentity Failed') - if cb ~= nil then - cb({}) - else - TriggerClientEvent('SonoranCAD::frameworksupport:returnIdentity', target, {}) - end - end - end - - -- Helper function that just returns the current job as a callback - function GetCurrentJob(player, cb) - local currentJob = '' - if cb == nil then - if JobCache[tostring(player)] ~= nil then - debugLog('Return cached player') - return JobCache[tostring(player)] - else - debugLog(('Player %s has no cached job'):format(player)) - end - end - local xPlayer = nil - if pluginConfig.usingQBCore then - xPlayer = QBCore.Functions.GetPlayer(tonumber(player)) - else - xPlayer = ESX.GetPlayerFromId(player) - end - if xPlayer == nil then - warnLog(('Failed to obtain player info from %s. ESX.GetPlayerFromId returned nil.'):format(player)) - else - if pluginConfig.usingQBCore then - if not xPlayer.PlayerData.job.onduty then -- QBUS job.onduty is false when on duty??? okayyyyy - currentJob = xPlayer.PlayerData.job.name - else - currentJob = 'offduty' .. xPlayer.PlayerData.job.name - end - else - currentJob = xPlayer.job.name - end - debugLog('Returned job: ' .. tostring(currentJob)) - end - if cb == nil then - JobCache[tostring(player)] = currentJob - return currentJob - elseif cb == true then - JobCache[tostring(player)] = currentJob - debugLog('refreshed job cache for player ' .. player .. '-' .. currentJob) - else - cb(currentJob) - end - end - - -- Caching functionality, used locally to reduce database load - CreateThread(function() - while ESX == nil do - Wait(10) - end - local xPlayers = nil - if pluginConfig.usingQBCore then - xPlayers = QBCore.Functions.GetPlayers() - else - xPlayers = ESX.GetPlayers() - end - for i = 1, #xPlayers, 1 do - local player = nil - if pluginConfig.usingQBCore then - player = QBCore.Functions.GetPlayers(tonumber(xPlayers[i])) - else - player = ESX.GetPlayerFromId(xPlayers[i]) - end - if player == nil then - debugLog('Failed to obtain job from player ' .. tostring(xPlayers[i])) - else - if pluginConfig.usingQBCore then - if not player.PlayerData.job.onduty then - JobCache[tostring(player)] = player.PlayerData.job.name - else - JobCache[tostring(player)] = 'offduty' .. player.PlayerData.job.name - end - else - JobCache[tostring(player)] = player.job.name - end - end - end - Wait(30000) - end) - - AddEventHandler('playerDropped', function() - JobCache[tostring(source)] = nil - end) - - -- Event for clients to request esx_identity information from the server - RegisterNetEvent('SonoranCAD::frameworksupport:getIdentity') - AddEventHandler('SonoranCAD::frameworksupport:getIdentity', function() - GetIdentity(source) - end) - - -- Event for clients to trigger job refresh on server (primarily for QBUS onduty handling) - RegisterNetEvent('SonoranCAD::frameworksupport:refreshJobCache') - AddEventHandler('SonoranCAD::frameworksupport:refreshJobCache', function() - local src = source - GetCurrentJob(src, true) - end) - - -- EVENT_RECORD_ADDED - RegisterServerEvent('SonoranCAD::pushevents:RecordAdded') - AddEventHandler('SonoranCAD::pushevents:RecordAdded', function(record) - -- Check to see if we should be issuing fines. - if not pluginConfig.issueFines then - return - end - debugLog('Receieved new record') - - local isFineable = false - for _, formName in pairs(pluginConfig.fineableForms) do - if record.name:upper() == formName:upper() then - isFineable = true - end - end - if isFineable then - -- Create empty citation object - local citation = {issuer = nil, -- Issuer of the fine - first = nil, -- First name of the fine target - last = nil, -- Last name of the fine target - fine = 0, -- Total sum of all fineable offenses - department = nil} - debugLog(record.name:upper() .. ' is a fineable record.') - -- Iterate the sections of the record - for k, sec in pairs(record.sections) do - -- Iterate the fields of the record section - for _, field in pairs(sec.fields) do - -- Store the first name of the fine target - if field.uid == 'first' then - citation.first = field.value - end - -- Store the last name of the fine target - if field.uid == 'last' then - citation.last = field.value - end - -- Retrieve the new Unit Name from the Agency Information - if field.type == 'UNIT_NAME' then - citation.issuer = field.value - end - -- Get "Special" fields from the report - if field.type == 'UNIT_DEPARTMENT' then - citation.department = field.value - end - if field.label == 'New Field Name' then - if field.data then - -- Get and store the name of the issuing officer to the citation - if field.data.officer then - citation.issuer = field.data.officer - end - -- Get and add speeding charges to the citation - if field.data.fine then - citation.fine = citation.fine + tonumber(field.data.fine) - debugLog('Added fine of $' .. field.data.fine .. ' for ' .. field.data.vehicleSpeed .. ' in a ' .. field.data.speedLimit .. 'zone.') - end - -- Get and add other charges to the citation - if field.data.charges then - for _, charge in pairs(field.data.charges) do - local fineTotal = tonumber(charge.arrestBondAmount) * charge.arrestChargeCounts - citation.fine = citation.fine + tonumber(fineTotal) - debugLog('Added fine of $' .. fineTotal .. ' for ' .. charge.arrestChargeCounts .. ' counts of ' .. charge.arrestCharge) - end - end - end - end - end - end - - debugLog('New Citation to Issue:') - debugLog('Issuer: ' .. tostring(citation.issuer)) - debugLog('Issued To: ' .. tostring(citation.first) .. ' ' .. tostring(citation.last)) - debugLog('Total Fines: $' .. tostring(citation.fine)) - - -- If the citation is missing a first name or a last name we can't issue the fine. - if citation.first == '' or citation.last == '' then - return - end - - -- Find the civilian that matches the citation and issue them a fine. - if pluginConfig.usingQBCore then - xPlayers = QBCore.Functions.GetPlayers() - else - xPlayers = ESX.GetPlayers() - end - - for i = 1, #xPlayers, 1 do - GetIdentity(xPlayers[i], function(xPlayer) - if pluginConfig.usingQBCore then - if xPlayer.PlayerData.charinfo.firstname == citation.first then - if xPlayer.PlayerData.charinfo.lastname == citation.last then - debugLog('found player online matching fined character') - xPlayer.Functions.RemoveMoney('bank', citation.fine) - if pluginConfig.usingQBManagement then - if pluginConfig.qbManagementAccountNames[citation.department] ~= nil then - exports['qb-management']:AddMoney(pluginConfig.qbManagementAccountNames[citation.department], citation.fine) - end - end - if pluginConfig.fineNotify then - debugLog('sending fine notification') - local finemessage = citation.first .. ' ' .. citation.last .. ' has been issued a fine of $' .. citation.fine - if citation.issuer ~= '' then - finemessage = finemessage .. ' by ' .. citation.issuer - end - TriggerClientEvent('chat:addMessage', -1, {color = {255, 0, 0}, multiline = true, args = {finemessage}}) - end - if pluginConfig.qbNotifyFinedPlayer then - TriggerClientEvent('QBCore:Notify', xPlayer.PlayerData.source, pluginConfig.qbFineMessage:gsub('$AMOUNT', citation.fine):gsub('$OFFICER_NAME', citation.issuer), 'error', 5000) - end - end - end - else - if xPlayer.getName() == citation.first .. ' ' .. citation.last then - debugLog('found player online matching fined character') - xPlayer.removeAccountMoney('bank', citation.fine) - ESX.SavePlayer(xPlayer) - if pluginConfig.fineNotify then - debugLog('sending fine notification') - local finemessage = xPlayer.getName() .. ' has been issued a fine of $' .. citation.fine - if citation.issuer ~= '' then - finemessage = finemessage .. ' by ' .. citation.issuer - end - TriggerClientEvent('chat:addMessage', -1, {color = {255, 0, 0}, multiline = true, args = {finemessage}}) - end - end - end - end) - end - end - end) - end - - end) -end) diff --git a/resources/[sonorancad]/sonorancad/submodules/kick/cl_kick.lua b/resources/[sonorancad]/sonorancad/submodules/kick/cl_kick.lua deleted file mode 100644 index 53481ca50..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/kick/cl_kick.lua +++ /dev/null @@ -1,15 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: kick - Creator: Taylor McGaw - Description: Kicks user from the cad upon exiting the server -]] -local pluginConfig = Config.GetPluginConfig("kick") - -if pluginConfig.enabled then ---------------------------------------------------------------------------- --- Chat Suggestions **DO NOT EDIT UNLESS YOU KNOW WHAT YOU ARE DOING** ---------------------------------------------------------------------------- - -end \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/kick/sv_kick.lua b/resources/[sonorancad]/sonorancad/submodules/kick/sv_kick.lua deleted file mode 100644 index bf348dcc3..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/kick/sv_kick.lua +++ /dev/null @@ -1,42 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: kick - Creator: Taylor McGaw - Description: Kicks user from the cad upon exiting the server -]] - -local pluginConfig = Config.GetPluginConfig("kick") - -if pluginConfig.enabled then - - local PendingKicks = {} - registerApiType("KICK_UNIT", "emergency") - AddEventHandler("playerDropped", function() - local source = source - local identifier = GetIdentifiers(source)[Config.primaryIdentifier] - if not identifier then - debugLog("kick: no API ID, skip") - return - end - table.insert(PendingKicks, identifier) - end) - - CreateThread(function() - while true do - if #PendingKicks > 0 then - local kicks = {} - while true do - local pendingKick = table.remove(PendingKicks) - if pendingKick ~= nil then - table.insert(kicks, {["apiId"] = pendingKick, ["reason"] = "You have exited the server", ["serverId"] = Config.serverId}) - else - break - end - end - performApiRequest(kicks, 'KICK_UNIT', function() end) - end - Wait(10000) - end - end) -end \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/locations/cl_locations.lua b/resources/[sonorancad]/sonorancad/submodules/locations/cl_locations.lua deleted file mode 100644 index 3013a5567..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/locations/cl_locations.lua +++ /dev/null @@ -1,82 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: locations - Creator: SonoranCAD - Description: Implements location updating for players -]] -CreateThread(function() Config.LoadPlugin("locations", function(pluginConfig) - - if pluginConfig.enabled then - - local currentLocation = '' - local lastLocation = 'none' - local lastSentTime = nil - local lastCoords = { x = 0, y = 0, z = 0 } - - local function sendLocation() - local pos = GetEntityCoords(PlayerPedId()) - local var1, var2 = GetStreetNameAtCoord(pos.x, pos.y, pos.z, Citizen.ResultAsInteger(), Citizen.ResultAsInteger()) - local postal = nil - if isPluginLoaded("postals") then - postal = getNearestPostal() - else - pluginConfig.prefixPostal = false - end - local l1 = GetStreetNameFromHashKey(var1) - local l2 = GetStreetNameFromHashKey(var2) - if l2 ~= '' then - currentLocation = l1 .. ' / ' .. l2 - else - currentLocation = l1 - end - if (bodyCamOn or currentLocation ~= lastLocation or vector3(pos.x, pos.y, pos.z) ~= vector3(lastCoords.x, lastCoords.y, lastCoords.z)) then - -- Location changed, continue - local toSend = currentLocation - if pluginConfig.prefixPostal and postal ~= nil then - toSend = "["..tostring(postal).."] "..currentLocation - elseif postal == nil and pluginConfig.prefixPostal == true then - debugLog("Unable to send postal because I got a null response from getNearestPostal()?!") - end - if bodyCamOn then - TriggerServerEvent('SonoranCAD::locations:SendLocation', toSend, pos, bodyCamFrequency) - else - TriggerServerEvent('SonoranCAD::locations:SendLocation', toSend, pos) - end - lastCoords = pos - debugLog(("Locations different, sending. (%s ~= %s) SENT: %s (POS: %s)"):format(currentLocation, lastLocation, toSend, json.encode(lastCoords))) - lastSentTime = GetGameTimer() - lastLocation = currentLocation - end - end - - Citizen.CreateThread(function() - -- Wait for plugins to settle - Wait(5000) - while true do - while not NetworkIsPlayerActive(PlayerId()) do - Wait(10) - end - sendLocation() - -- Wait (1000ms) before checking for an updated unit location - Citizen.Wait(pluginConfig.checkTime) - end - end) - - Citizen.CreateThread(function() - while lastSentTime == nil do - while not NetworkIsPlayerActive(PlayerId()) do - Wait(10) - end - Wait(15000) - if lastSentTime == nil then - TriggerServerEvent("SonoranCAD::locations:ErrorDetection", true) - warnLog("Warning: No location data has been sent yet. Check for errors.") - end - Wait(30000) - end - end) - - end - - end) end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/locations/sv_locations.lua b/resources/[sonorancad]/sonorancad/submodules/locations/sv_locations.lua deleted file mode 100644 index 4c20f2946..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/locations/sv_locations.lua +++ /dev/null @@ -1,82 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: locations - Creator: SonoranCAD - Description: Implements location updating for players -]] -CreateThread(function() Config.LoadPlugin("locations", function(pluginConfig) - - if pluginConfig.enabled then - -- Pending location updates array - LocationCache = {} - local LastSend = 0 - - -- Main api POST function - local function SendLocations() - while true do - local cache = {} - for k, v in pairs(LocationCache) do - if v.isUpdated ~= nil then - v.isUpdated = nil - table.insert(cache, v) - end - end - if #cache > 0 then - if GetGameTimer() > LastSend+5000 then - performApiRequest(cache, 'UNIT_LOCATION', function() end) - LastSend = GetGameTimer() - else - debugLog(("UNIT_LOCATION: Attempted to send data too soon. %s !> %s"):format(GetGameTimer(), LastSend+5000)) - end - end - Wait(Config.postTime+500) - end - end - - function findPlayerLocation(playerSrc) - if LocationCache[playerSrc] ~= nil then - return LocationCache[playerSrc].location - end - return nil - end - - -- Main update thread sending api location update POST requests per the postTime interval - Citizen.CreateThread(function() - Wait(1) - SendLocations() - end) - - -- Event from client when location changes occur - RegisterServerEvent('SonoranCAD::locations:SendLocation') - AddEventHandler('SonoranCAD::locations:SendLocation', function(currentLocation, position, bodycamFrequency) - local source = source - local identifier = GetIdentifiers(source)[Config.primaryIdentifier] - if identifier == nil then - debugLog(("user %s has no identifier for %s, skipped."):format(source, Config.primaryIdentifier)) - return - end - if bodycamFrequency then - local frameNumber = latestFrame[source] - LocationCache[source] = {['apiId'] = identifier, ['location'] = currentLocation, ['coordinates'] = position, ['isUpdated'] = true, ['bodyFrequency'] = bodycamFrequency, ['proxyUrl'] = Config.proxyUrl, ['bodyFrame'] = frameNumber} - else - LocationCache[source] = {['apiId'] = identifier, ['location'] = currentLocation, ['coordinates'] = position, ['isUpdated'] = true} - end - end) - - AddEventHandler("playerDropped", function() - local source = source - LocationCache[source] = nil - end) - - RegisterNetEvent("SonoranCAD::locations:ErrorDetection") - AddEventHandler("SonoranCAD::locations:ErrorDetection", function(isInitial) - if isInitial then - errorLog(("Player %s reported an error sending initial location data. Check client logs for errors. Did you set up the postals plugin correctly?"):format(source)) - else - warnLog(("Player %s reported an error sending location data. Check client logs for errors."):format(source)) - end - end) - - end - end) end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/lookups/sv_lookups.lua b/resources/[sonorancad]/sonorancad/submodules/lookups/sv_lookups.lua deleted file mode 100644 index 6ea50616a..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/lookups/sv_lookups.lua +++ /dev/null @@ -1,303 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: lookups - Creator: SonoranCAD - Description: Implements the name/plate lookup API -]] - -local pluginConfig = Config.GetPluginConfig("lookups") - -if pluginConfig.enabled then - - registerApiType("LOOKUP", "general") - - local LookupCache = {} - - local Lookup = { - first = nil, - last = nil, - mi = nil, - plate = nil, - types = nil, - lastFetched = nil - } - function Lookup.Create(first, last, mi, plate, types, response) - local self = shallowcopy(Lookup) - self.first = first - self.last = last - self.mi = mi - self.plate = plate - self.types = types - self.lastFetched = GetGameTimer() - self.response = response - return self - end - function Lookup:UpdateCache() - self.response = info - self.lastFetched = GetGameTimer() - end - function Lookup:IsMatch(first, last, mi, plate, types) - if self.first == first and self.last == last and self.mi == mi and self.plate == plate then - for _, v in pairs(self.types) do - local match = false - for __, v2 in pairs(types) do - if v2 == v then - match = true - end - end - if not match then - return false - end - end - return true - else - return false - end - end - - -- Stale lookup garbage collector - local function PurgeStaleLookups() - local currentTime = GetGameTimer() - for k, v in pairs(LookupCache) do - local garbageTime = v.lastFetched + (pluginConfig.maxCacheTime*1000) - if currentTime >= garbageTime then - LookupCache[k] = nil - debugPrint(("Stale lookup purged %s"):format(k)) - end - end - SetTimeout(pluginConfig.stalePurgeTimer*1000, PurgeStaleLookups) - end - - PurgeStaleLookups() - - function cadLookup(data, callback, autoLookup) - -- check if the lookupData has all required fields - data["first"] = data["first"] == nil and "" or data["first"] - data["mi"] = data["mi"] == nil and "" or data["mi"] - data["last"] = data["last"] == nil and "" or data["last"] - data["plate"] = data["plate"] == nil and "" or data["plate"]:match("^%s*(.-)%s*$") - data["types"] = data["types"] == nil and {2,3,4,5} or data["types"] - - if data.first == "" and data.last == "" and data.mi == "" and data.plate == "" then - --not a valid request, just return a blank lookup - debugLog("Invalid lookup, all blanks? Trace: "..debug.traceback()) - callback({}) - return - end - if autoLookup ~= nil then - data["apiId"] = autoLookup - else - for k, v in pairs(LookupCache) do - if v:IsMatch(data.first, data.last, data.mi, data.plate, data.types) then - debugLog("Returning cached response") - callback(json.decode(v.response)) - return - end - end - end - performApiRequest({data}, "LOOKUP", function(result) - debugLog("Performed lookup") - local lookup = json.decode(result) - local l = Lookup.Create(data.first, data.last, data.mi, data.plate, data.types, result) - table.insert(LookupCache, l) - callback(lookup) - end) - - end - - function cadLookupInt(searchType, value, types, callback, autoLookup) - - end - - --[[ - cadNameLookup - first: First Name - last: Last Name - mi: Middle Initial - callback: function called with return data - ]] - function cadNameLookup(first, last, mi, callback) - local data = {} - data.first = first - data.last = last - data.mi = mi - cadLookup(data, callback, autoLookup) - end - - --[[ - cadPlateLookup - plate: plate number - basicFlag: deprecated - callback: the function called with the return data - autoLookup: when populated with an API ID, pops open a search window on the officer's CAD (optional) - ]] - function cadPlateLookup(plate, basicFlag, callback, autoLookup) - local data = {} - data["plate"] = plate - if autoLookup ~= nil then - data["apiId"] = autoLookup - end - cadLookup(data, callback, autoLookup) - - end - - function cadGetInformation(plate, callback, autoLookup) - local data = {} - data["plate"] = plate - if autoLookup ~= nil then - data["apiId"] = autoLookup - end - cadLookup(data, function(result) - local regData = {} - local charData = {} - local vehData = {} - local boloData = {} - local warrantData = {} - if result ~= nil then - for k, v in pairs(result) do - for _, record in pairs(v.sections) do - if v.type == 5 then - debugLog("Record type 5") - -- detect fields to find registration info - for k, field in pairs(record.fields) do - if field.uid == "status" and field.type == "select" then - debugLog("Found registration data") - local reg = {} - for k, field in pairs(record.fields) do - if field["uid"] ~= nil then - if string.match(field.uid, "_") then - reg[field.label:lower()] = field.value - debugLog(("set %s = %s"):format(field.label:lower(), field.value)) - else - reg[field.uid] = field.value - debugLog(("set %s = %s"):format(field.uid, field.value)) - end - end - end - table.insert(regData, reg) - elseif field.uid == "first" then - debugLog("found civilian info") - local char = {} - for _, field in pairs(record.fields) do - if field["uid"] ~= nil then - if string.match(field.uid, "_") then - char[field.label:lower()] = field.value - else - char[field.uid] = field.value - end - end - end - table.insert(charData, char) - elseif field.uid == "plate" then - debugLog("found vehicle info") - local veh = {} - for _, field in pairs(record.fields) do - if field["uid"] ~= nil then - if string.match(field.uid, "_") then - veh[field.label:lower()] = field.value - else - veh[field.uid] = field.value - end - end - end - table.insert(vehData, veh) - end - end - elseif v.type == 3 then - local boloActive = true - for _, section in pairs(v.sections) do - for _, field in pairs(section.fields) do - if field.uid == "status" then - debugLog(("Found BOLO status field %s with value %s"):format(field.label, field.value)) - if field.value == "0" then - boloActive = true - elseif field.value == "1" then - boloActive = false - end - end - end - if section.category == 1 then-- flags - if section.fields.data ~= nil and section.fields.data.flags ~= nil then - boloData = section.fields.data.flags - else - boloData = {"BOLO"} - end - end - end - if boloActive and (boloData == nil or #boloData == 0) then - boloData = {"BOLO"} - end - if not boloActive then - debugLog("BOLO inactive, mark as such") - boloData = {} - end - elseif v.type == 2 then - local warrantActive = true - for _, section in pairs(v.sections) do - for _, field in pairs(section.fields) do - if field.uid == "status" then - debugLog(("Found Warrant status field %s with value %s"):format(field.label, field.value)) - if field.value == "0" then - warrantActive = true - elseif field.value == "1" then - warrantActive = false - end - end - end - if section.category == 1 then-- flags - if section.fields[1].data ~= nil and section.fields[1].data.flags ~= nil then - warrantData = section.fields[1].data.flags - else - warrantData = {"Warrant"} - end - end - end - if warrantActive and (warrantData == nil or #warrantData == 0) then - warrantData = {"Warrant"} - end - if not warrantActive then - debugLog("Warrant inactive, mark as such") - warrantData = {} - end - end - end - end - end - callback(regData, vehData, charData, boloData, warrantData) - end, autoLookup) - end - - exports('cadNameLookup', cadNameLookup) - exports('cadPlateLookup', cadPlateLookup) - - -- The follow two commands are for developer use to analyze API responses - - RegisterCommand("platefind", function(source, args, rawCommand) - if args[1] ~= nil then - cadGetInformation(args[1], function(regData, vehData, charData, boloData) - for _, veh in pairs(vehData) do - if veh.plate:lower() == args[1]:lower() then - reg = veh - print("Got registration data "..veh.plate) - print(json.encode(veh)) - print(json.encode(regData)) - break - end - end - end) - end - end, true) - - RegisterCommand("namefind", function(source, args, rawCommand) - if args[1] ~= nil then - local firstName = args[1] - local lastName = args[2] ~= nil and args[2] or "" - local mi = args[3] ~= nil and args[3] or "" - cadNameLookup(firstName, lastName, mi, function(data) - print(("Raw data: %s"):format(json.encode(data))) - end) - end - end, true) - -end \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/postals/cl_postals.lua b/resources/[sonorancad]/sonorancad/submodules/postals/cl_postals.lua deleted file mode 100644 index 66eb2d967..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/postals/cl_postals.lua +++ /dev/null @@ -1,79 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: postals - Creator: SonoranCAD - Description: Fetches nearest postal from client -]] - -CreateThread(function() - Config.LoadPlugin('postals', function(pluginConfig) - local lastPostal = nil - local eventPostal = nil - if pluginConfig.enabled then - -- Don't touch this! - function getNearestPostal() - if pluginConfig.mode and pluginConfig.mode == 'event' then - return eventPostal - elseif pluginConfig.mode and pluginConfig.mode == 'file' then - local postalFile = LoadResourceFile(GetCurrentResourceName(), ('/submodules/postals/%s'):format(pluginConfig.customPostalCodesFile)) - if postalFile ~= nil then - local postalData = json.decode(postalFile) - for i, postal in ipairs(postalData) do postalData[i] = { vec(postal.x, postal.y), code = postal.code } end - local coords = GetEntityCoords(PlayerPedId()) - local _nearestIndex, _nearestD - coords = vec(coords[1], coords[2]) - local _total = #postalData - for i = 1, _total do - local D = #(coords - postalData[i][1]) - if not _nearestD or D < _nearestD then - _nearestIndex = i - _nearestD = D - end - end - local _code = postalData[_nearestIndex].code - return _code - else - assert(false, 'Custom postal file not found. Cannot use postals plugin.') - end - else - if exports[pluginConfig.nearestPostalResourceName] ~= nil then - local p = exports[pluginConfig.nearestPostalResourceName]:getPostal() - return p - else - assert(false, 'Required postal resource is not loaded. Cannot use postals plugin.') - end - end - end - if pluginConfig.mode and pluginConfig.nearestPostalEvent and pluginConfig.mode == 'event' then - AddEventHandler(pluginConfig.nearestPostalEvent, function(postal) - eventPostal = postal - end) - end - local function sendPostalData() - local postal = getNearestPostal() - if postal ~= nil and postal ~= lastPostal then - TriggerServerEvent('cadClientPostal', postal) - lastPostal = postal - end - end - CreateThread(function() - while not NetworkIsPlayerActive(PlayerId()) or pluginConfig.sendTimer == nil do - Wait(10) - end - TriggerServerEvent('getShouldSendPostal') - while true do - if pluginConfig.shouldSendPostalData then - sendPostalData() - end - Wait(pluginConfig.sendTimer) - end - end) - RegisterNetEvent('getShouldSendPostalResponse') - AddEventHandler('getShouldSendPostalResponse', function(toggle) - print('got ' .. tostring(toggle)) - pluginConfig.shouldSendPostalData = toggle - end) - end - end) -end) diff --git a/resources/[sonorancad]/sonorancad/submodules/postals/sv_postals.lua b/resources/[sonorancad]/sonorancad/submodules/postals/sv_postals.lua deleted file mode 100644 index e8800cba3..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/postals/sv_postals.lua +++ /dev/null @@ -1,119 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: postals - Creator: SonoranCAD - Description: Fetches nearest postal from client -]] -- Toggles Postal Sender -CreateThread(function() - Config.LoadPlugin('postals', function(pluginConfig) - local locationsConfig = Config.GetPluginConfig('locations') - - if pluginConfig.enabled and locationsConfig ~= nil then - - local postalFile = nil - local postals - local state = GetResourceState(pluginConfig.nearestPostalResourceName) - local shouldStop = false - if pluginConfig.mode and pluginConfig.mode == 'resource' then - if state ~= 'started' then - if state == 'missing' then - logError('POSTAL_RESOURCE_MISSING', getErrorText('POSTAL_RESOURCE_MISSING'):format(pluginConfig.nearestPostalResourceName)) - shouldStop = true - elseif state == 'stopped' then - logError('POSTAL_RESOURCE_STOPPED', getErrorText('POSTAL_RESOURCE_STOPPED'):format(pluginConfig.nearestPostalResourceName, state)) - else - logError('POSTAL_RESOURCE_BAD_STATE', getErrorText('POSTAL_RESOURCE_BAD_STATE'):format(pluginConfig.nearestPostalResourceName, state)) - shouldStop = true - end - else - postalFile = LoadResourceFile(pluginConfig.nearestPostalResourceName, GetResourceMetadata(pluginConfig.nearestPostalResourceName, 'postal_file')) - if postalFile == nil then - logError('POSTAL_CUSTOM_RESOURCE_FILE_ERROR', getErrorText('POSTAL_CUSTOM_RESOURCE_FILE_ERROR'):format(pluginConfig.nearestPostalResourceName, pluginConfig.nearestPostalResourceName)) - end - end - elseif pluginConfig.mode and pluginConfig.mode == 'file' then - postalFile = LoadResourceFile(GetCurrentResourceName(), ('/submodules/postals/%s'):format(pluginConfig.customPostalCodesFile)) - if postalFile == nil then - logError('CUSTOM_POSTALS_FILE_NOT_FOUND', geterrorText('CUSTOM_POSTALS_FILE_NOT_FOUND'):format(pluginConfig.customPostalCodesFile)) - shouldStop = true - end - end - if postalFile == nil then - logError('POSTAL_FILE_READ_ERROR') - shouldStop = true - end - if shouldStop then - pluginConfig.enabled = false - pluginConfig.disableReason = 'postal resource incorrect' - errorLog('Force disabling plugin to prevent client errors.') - return - end - - postals = json.decode(postalFile) - for i, postal in ipairs(postals) do - postals[i] = {vec(postal.x, postal.y), code = postal.code} - end - - PostalsCache = {} - - RegisterNetEvent('getShouldSendPostal') - AddEventHandler('getShouldSendPostal', function() - TriggerClientEvent('getShouldSendPostalResponse', source, locationsConfig.prefixPostal) - end) - - RegisterNetEvent('cadClientPostal') - AddEventHandler('cadClientPostal', function(postal) - PostalsCache[source] = postal - end) - - AddEventHandler('playerDropped', function(player) - PostalsCache[player] = nil - end) - - function getNearestPostal(player) - return PostalsCache[player] - end - - exports('cadGetNearestPostal', getNearestPostal) - - registerApiType('SET_POSTALS', 'general') - - CreateThread(function() - while Config.apiVersion == -1 or postals == nil do - Wait(1000) - end - if Config.apiVersion < 4 or not Config.apiSendEnabled then - return - end - performApiRequest(postalFile, 'SET_POSTALS', function() - end) - end) - - function getPostalFromVector3(coords) - if not coords or postals == nil then - return nil - end - local _total = #postals - local _nearestIndex, _nearestD - coords = vector2(coords.x, coords.y) - - for i = 1, _total do - local D = #(coords - postals[i][1]) - if not _nearestD or D < _nearestD then - _nearestIndex = i - _nearestD = D - end - end - - return postals[_nearestIndex].code - end - - elseif locationsConfig == nil then - errorLog('ERROR: Postals plugin is loaded, but required locations plugin is not. This plugin will not function correctly!') - pluginConfig.enabled = false - pluginConfig.disableReason = 'locations plugin missing' - end - - end) -end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/sonrad/cl_sonrad.lua b/resources/[sonorancad]/sonorancad/submodules/sonrad/cl_sonrad.lua deleted file mode 100644 index bf6984fc3..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/sonrad/cl_sonrad.lua +++ /dev/null @@ -1,20 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: sonrad - Creator: Sonoran Software Systems - Description: Sonoran Radio integration plugin - - Put all client-side logic in this file. -]] - -CreateThread(function() - Config.LoadPlugin("sonrad", function(pluginConfig) - - if pluginConfig.enabled then - - - - end - end) -end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/sonrad/sv_sonrad.lua b/resources/[sonorancad]/sonorancad/submodules/sonrad/sv_sonrad.lua deleted file mode 100644 index 971ed9356..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/sonrad/sv_sonrad.lua +++ /dev/null @@ -1,364 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: sonrad - Creator: Sonoran Software Systems - Description: Sonoran Radio integration plugin - - Put all server-side logic in this file. -]] - -CreateThread(function() Config.LoadPlugin("sonrad", function(pluginConfig) - - if pluginConfig.enabled then - - local CallCache = {} - local UnitCache = {} - local TowerCache = {} - - - if Config.apiVersion > 3 then - -- Register Api Types - registerApiType("ADD_BLIP", "emergency") - registerApiType("MODIFY_BLIP", "emergency") - registerApiType("REMOVE_BLIP", "emergency") - registerApiType("GET_BLIPS", "emergency") - - BlipMan = { - addBlip = function(coords, radius, colorHex, subType, toolTip, icon, dataTable, cb) - local data = {{ - ["serverId"] = GetConvar("sonoran_serverId", 1), - ["blip"] = { - ["id"] = -1, - ["subType"] = subType, - ["coordinates"] = { - ["x"] = coords.x, - ["y"] = coords.y - }, - ["radius"] = radius, - ["icon"] = icon, - ["color"] = colorHex, - ["tooltip"] = toolTip, - ["data"] = dataTable - } - }} - - performApiRequest(data, "ADD_BLIP", function(res) - if cb ~= nil then - cb(res) - end - end) - end, - - addBlips = function(blips, cb) - performApiRequest(blips, "ADD_BLIP", function(res) - if cb ~= nil then - cb(res) - end - end) - end, - - removeBlip = function(ids, cb) - performApiRequest({{ - ["ids"] = ids - }}, "REMOVE_BLIP", function(res) - if cb ~= nil then - cb(res) - end - end) - end, - - modifyBlips = function(dataTable, cb) - performApiRequest(dataTable, "MODIFY_BLIP", function(res) - if cb ~= nil then - cb(res) - end - end) - end, - - getBlips = function(cb) - local data = {{ - ["serverId"] = GetConvar("sonoran_serverId", 1) - }} - performApiRequest(data, "GET_BLIPS", function(res) - if cb ~= nil then - cb(res) - end - end) - end, - - removeWithSubtype = function(subType, cb) - BlipMan.getBlips(function(res) - local dres = json.decode(res) - local ids = {} - for _, v in ipairs(dres) do - if v.subType == subType then - table.insert(ids, #ids + 1, v.id) - end - end - BlipMan.removeBlip(ids, cb) - end) - end, - } - - function GetTower(coords) - for i = 1, #TowerCache do - if TowerCache[i].PropPosition == coords then - return TowerCache[i], i - end - end - return nil, nil - end - function GetTowerFromId(id) - for i, t in ipairs(TowerCache) do - if t.Id == id then - return t, i - end - end - end - function GetTowerCapacity(tower) - if #tower.DishStatus < 1 then - return 1.0 - end - - local n = 0.0 - for i = 1, #tower.DishStatus do - if tower.DishStatus[i] == 'alive' then - n = n + 1.0 - end - end - return n / #tower.DishStatus - end - - RegisterNetEvent("SonoranCAD::sonrad:SyncTowers") - AddEventHandler("SonoranCAD::sonrad:SyncTowers", function(Towers) - BlipMan.removeWithSubtype("repeater", function(res) - debugLog(res) - - TowerCache = Towers - - local BlipQueue = {} - - debugLog(json.encode(TowerCache)) - for _,t in ipairs(TowerCache) do - - if t.NotPhysical then - -- Handling for Mobile Repeaters - title = "Mobile Repeater" - color = "#ff00f6" - status = "MOBILE" - else - -- Handling for Stationary Repeaters - title = "Radio Tower" - color = "#00a6ff" - status = "HEALTHY" - end - - local CurrentBlip = { - ["serverId"] = GetConvar("sonoran_serverId", 1), - ["blip"] = { - ["id"] = -1, - ["subType"] = "repeater", - ["coordinates"] = { - ["x"] = t.PropPosition.x, - ["y"] = t.PropPosition.y - }, - ["radius"] = t.Range * 0.7937, - ["icon"] = "https://sonoransoftware.com/assets/images/icons/email/radio.png", - ["color"] = color, - ["tooltip"] = title, - ["data"] = { - { - ["title"] = "Status", - ["text"] = status, - } - } - } - } - - table.insert(BlipQueue, #BlipQueue + 1, CurrentBlip) - end - - BlipMan.addBlips(BlipQueue, function(res) - local blips = json.decode(res) - for i=1, #TowerCache do - TowerCache[i].BlipID = blips[i].id - end - debugLog("Tower Cache:" .. json.encode(TowerCache)) - end) - end) - end) - - CreateThread(function() - while true do - Wait(5000) - for i=1, #TowerCache do - if TowerCache[i].Modified then - debugLog("Change found during batch... Sending") - TowerCache[i].Modified = false - local color = nil - local status = nil - local title = nil - if TowerCache[i].NotPhysical then - -- Handling for Mobile Repeaters - title = "Mobile Repeater" - color = "#ff00f6" - status = "MOBILE" - else - -- Handling for Stationary Repeaters - title = "Radio Tower" - color = "#00a6ff" - status = "HEALTHY" - end - local data = {{ - ["id"] = TowerCache[i].BlipID, - ["subType"] = "repeater", - ["coordinates"] = { - ["x"] = TowerCache[i].PropPosition.x, - ["y"] = TowerCache[i].PropPosition.y - }, - ["radius"] = TowerCache[i].Range * 0.7937, - ["icon"] = "https://sonoransoftware.com/assets/images/icons/email/radio.png", - ["color"] = color, - ["tooltip"] = title, - ["data"] = { - { - ["title"] = "Health", - ["text"] = status - } - } - }} - BlipMan.modifyBlips(data, function(res) - debugLog(res) - end) - else - --debugLog("No changes during batch... Ignoring") - end - end - end - end) - - RegisterNetEvent("SonoranCAD::sonrad:SyncOneTower") - AddEventHandler("SonoranCAD::sonrad:SyncOneTower", function(towerId, newTower) - local oldTower, towerIndex = GetTowerFromId(towerId) - local BlipID = oldTower.BlipID - if oldTower.PropPosition.x == newTower.PropPosition.x and oldTower.PropPosition.y == newTower.PropPosition.y then - --debugLog("No Changes During Sync... Ignoring" .. towerIndex) - else - debugLog("Changes found during sync... Queuing" .. towerIndex) - TowerCache[towerIndex] = newTower - TowerCache[towerIndex].BlipID = BlipID - TowerCache[towerIndex].Modified = true - end - end) - - RegisterNetEvent("SonoranCAD::sonrad:SetDishStatus") - AddEventHandler("SonoranCAD::sonrad:SetDishStatus", function(towerId, dishStatus) - local tower = GetTowerFromId(towerId) - if not tower then return end - tower.DishStatus = dishStatus - local pct = GetTowerCapacity(tower) - local color = nil - local status = nil - if pct == 1 then - -- Tower is alive and well. - debugLog("TOWER IS HEALTHY") - color = "#00a6ff" - status = "HEALTHY" - elseif pct == 0 then - -- Tower is offline - debugLog("TOWER IS OFFLINE") - color = "#ff0000" - status = "OFFLINE" - else - -- Tower is degraded - debugLog("TOWER IS DEGRADED") - color = "#ff8c00" - status = "DEGRADED" - end - - local data = {{ - ["id"] = tower.BlipID, - ["subType"] = "repeater", - ["coordinates"] = { - ["x"] = tower.PropPosition.x, - ["y"] = tower.PropPosition.y - }, - ["radius"] = tower.Range * 0.7937, - ["icon"] = "https://sonoransoftware.com/assets/images/icons/email/radio.png", - ["color"] = color, - ["tooltip"] = "Radio Tower", - ["data"] = { - { - ["title"] = "Health", - ["text"] = status, - } - } - }} - BlipMan.modifyBlips(data, function(res) - debugLog(res) - end) - end) - else - debugLog("Disabling blip management, API version too low.") - end - - - CreateThread(function() - while true do - Wait(5000) - CallCache = GetCallCache() - UnitCache = GetUnitCache() - for k, v in pairs(CallCache) do - v.dispatch.units = {} - if v.dispatch.idents then - for ka, va in pairs(v.dispatch.idents) do - local unit - local unitId = GetUnitById(va) - table.insert(v.dispatch.units, UnitCache[unitId]) - end - end - end - end - end) - - RegisterNetEvent("SonoranCAD::sonrad:GetCurrentCall") - AddEventHandler("SonoranCAD::sonrad:GetCurrentCall", function() - local playerid = source - local unit = GetUnitByPlayerId(source) - -- print("unit: " .. json.encode(unit)) - for k, v in pairs(CallCache) do - if v.dispatch.idents then - -- print(json.encode(v)) - for ka, va in pairs(v.dispatch.idents) do - -- print("Comparing " .. unit.id .. " to " .. va) - if unit then - if unit.id == va then - TriggerClientEvent("SonoranCAD::sonrad:UpdateCurrentCall", source, v) - -- print("SonoranCAD::sonrad:UpdateCurrentCall " .. source .. " " .. json.encode(v)) - end - end - end - end - end - end) - - RegisterNetEvent("SonoranCAD::sonrad:RadioPanic") - AddEventHandler("SonoranCAD::sonrad:RadioPanic", function() - if not isPluginLoaded("callcommands") then - errorLog("Cannot process radio panic as the required callcommands plugin is not present.") - return - end - sendPanic(source, true) - end) - - RegisterNetEvent("SonoranCAD::sonrad:GetUnitInfo") - AddEventHandler("SonoranCAD::sonrad:GetUnitInfo", function() - local unit = GetUnitByPlayerId(source) - if unit then - TriggerClientEvent("SonoranCAD::sonrad:GetUnitInfo:Return", source, unit) - end - end) - end - -end) end) diff --git a/resources/[sonorancad]/sonorancad/submodules/trafficstop/cl_trafficstop.lua b/resources/[sonorancad]/sonorancad/submodules/trafficstop/cl_trafficstop.lua deleted file mode 100644 index aa5d50d44..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/trafficstop/cl_trafficstop.lua +++ /dev/null @@ -1,10 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: trafficstop - Creator: SonoranCAD - Description: Implements ts command -]] -CreateThread(function() Config.LoadPlugin("dispatchnotify", function(pluginConfig) - -end) end) \ No newline at end of file diff --git a/resources/[sonorancad]/sonorancad/submodules/trafficstop/sv_trafficstop.lua b/resources/[sonorancad]/sonorancad/submodules/trafficstop/sv_trafficstop.lua deleted file mode 100644 index 719ea2584..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/trafficstop/sv_trafficstop.lua +++ /dev/null @@ -1,96 +0,0 @@ ---[[ - Sonaran CAD Plugins - - Plugin Name: trafficstop - Creator: SonoranCAD - Description: Implements ts command -]] - -CreateThread(function() Config.LoadPlugin("trafficstop", function(pluginConfig) - -if pluginConfig.enabled then - - if pluginConfig.trafficCommand == nil then - pluginConfig.trafficCommand = "ts" - end - - registerApiType("NEW_DISPATCH", "emergency") - - -- Traffic Stop Handler - function HandleTrafficStop(type, source, args, rawCommand) - local identifier = GetIdentifiers(source)[Config.primaryIdentifier] - local index = findIndex(identifier) - local origin = pluginConfig.origin - local status = pluginConfig.status - local priority = pluginConfig.priority - local address = LocationCache[source] ~= nil and LocationCache[source].location or 'Unknown' - local postal = isPluginLoaded("postals") and getNearestPostal(source) or "" - local title = pluginConfig.title - local code = pluginConfig.code - local units = {identifier} - local tempNotes = {} - local notesStr = "" - address = address:gsub('%b[]', '') - -- Checking if there are any description arguments. - if args[1] then - local description = table.concat(args, " ") - if type == "ts" then - description = "Traffic Stop - "..description - if isPluginLoaded("wraithv2") and wraithLastPlates ~= nil then - if wraithLastPlates.locked ~= nil then - local plate = wraithLastPlates.locked.plate:gsub("%s+","") - table.insert(tempNotes, ("PLATE: %s"):format(plate)) - end - end - end - notesStr = table.concat(tempNotes, " ") - local notes = {} - if notesStr ~= "" then - notes = { - { ['time'] = "00:00:00", ['label'] = "Dispatch", ['type'] = "text", ['content'] = notesStr } - } - end - -- Sending the API event - TriggerEvent('SonoranCAD::trafficstop:SendTrafficApi', origin, status, priority, address, postal, title, code, description, units, notes, source) - -- Sending the user a message stating the call has been sent - TriggerClientEvent("chat:addMessage", source, {args = {"^0^5^*[SonoranCAD]^r ", "^7Details regarding you traffic Stop have been added to CAD"}}) - else - -- Throwing an error message due to now call description stated - TriggerClientEvent("chat:addMessage", source, {args = {"^0[ ^1Error ^0] ", "You need to specify Traffic Stop details (IE: vehicle Description)."}}) - end - end - - RegisterCommand(pluginConfig.trafficCommand, function(source, args, rawCommand) - HandleTrafficStop("ts", source, args, rawCommand) - end, pluginConfig.usePermissions) - - -- Client TraficStop request - RegisterServerEvent('SonoranCAD::trafficstop:SendTrafficApi') - AddEventHandler('SonoranCAD::trafficstop:SendTrafficApi', function(origin, status, priority, address, postal, title, code, description, units, notes, source) - -- send an event to be consumed by other resources - TriggerEvent("SonoranCAD::trafficstop:cadIncomingTraffic", origin, status, priority, address, postal, title, code, description, units, notes, source) - if Config.apiSendEnabled then - local data = { - ['serverId'] = Config.serverId, - ['origin'] = origin, - ['status'] = status, - ['priority'] = priority, - ['block'] = "", -- not used, but required - ['postal'] = postal, --TODO - ['address'] = address, - ['title'] = title, - ['code'] = code, - ['description'] = description, - ['units'] = units, - ['notes'] = notes -- required - } - debugLog("sending Traffic Stop!") - performApiRequest({data}, 'NEW_DISPATCH', function() end) - else - debugPrint("[SonoranCAD] API sending is disabled. Traffic Stop ignored.") - end - end) - -end - -end) end) diff --git a/resources/[sonorancad]/sonorancad/submodules/ts3integration/sv_ts3integration.js b/resources/[sonorancad]/sonorancad/submodules/ts3integration/sv_ts3integration.js deleted file mode 100644 index 5437d995d..000000000 --- a/resources/[sonorancad]/sonorancad/submodules/ts3integration/sv_ts3integration.js +++ /dev/null @@ -1,184 +0,0 @@ -/* - SonoranCAD FiveM - A SonoranCAD integration for FiveM servers - Copyright (C) 2020 Sonoran Software - -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 in the file "LICENSE". If not, see