From f03b9866ef867903ae6455dea139c3892531fc43 Mon Sep 17 00:00:00 2001 From: Musiker15 Date: Sun, 22 Sep 2024 11:42:36 +0200 Subject: [PATCH] Update v2.4.7 --- client/functions/disconnectlogger.lua | 2 +- client/functions/entities.lua | 112 ++++++++++++++++++ client/functions/input.lua | 33 +++--- client/functions/main.lua | 49 ++------ client/functions/numpad.lua | 31 +++-- client/functions/showCoords.lua | 31 +++-- client/functions/vehicle.lua | 157 ++++++++++++++++++++++++++ client/main.lua | 10 -- fxmanifest.lua | 6 +- html/css/notify.css | 2 +- server/functions/bansystem.lua | 4 +- server/functions/cronjobs.lua | 26 +++-- server/functions/disconnectlogger.lua | 2 +- server/functions/entities.lua | 59 ++++++++++ server/functions/main.lua | 110 +++++++++++------- server/functions/showCoords.lua | 27 +++-- server/functions/vehicle.lua | 35 ++++++ server/inventories/ox_inventory.lua | 2 +- server/main.lua | 3 +- server/versionchecker.lua | 4 +- shared/functions.lua | 47 ++++++++ shared/math.lua | 40 +++++++ shared/string.lua | 51 +++++++++ shared/table.lua | 148 ++++++++++++++++++++++++ 24 files changed, 837 insertions(+), 154 deletions(-) create mode 100644 client/functions/entities.lua create mode 100644 client/functions/vehicle.lua create mode 100644 server/functions/entities.lua create mode 100644 server/functions/vehicle.lua create mode 100644 shared/functions.lua create mode 100644 shared/math.lua create mode 100644 shared/string.lua create mode 100644 shared/table.lua diff --git a/client/functions/disconnectlogger.lua b/client/functions/disconnectlogger.lua index e6f6afe..4180889 100644 --- a/client/functions/disconnectlogger.lua +++ b/client/functions/disconnectlogger.lua @@ -52,4 +52,4 @@ local display = function(data) end end) end -RegisterNetEvent('msk_core:anticombatlog', display) \ No newline at end of file +RegisterNetEvent('msk_core:discLogger', display) \ No newline at end of file diff --git a/client/functions/entities.lua b/client/functions/entities.lua new file mode 100644 index 0000000..9252212 --- /dev/null +++ b/client/functions/entities.lua @@ -0,0 +1,112 @@ +GetEntities = function(isPlayerEntity) + local entities = {} + + if isPlayerEntity then + for _, player in ipairs(GetActivePlayers()) do + local ped = GetPlayerPed(player) + + if DoesEntityExist(ped) and ped ~= PlayerPedId() then + entities[player] = ped + end + end + else + entities = GetGamePool('CVehicle') + end + + return entities +end + +GetClosestEntity = function(isPlayerEntity, coords) + local closestEntity, closestDistance = -1, -1 + local entites = GetEntities(isPlayerEntity) + + if coords then + coords = vector3(coords.x, coords.y, coords.z) + else + coords = GetEntityCoords(PlayerPedId()) + end + + for k, entity in pairs(entites) do + local distance = #(coords - GetEntityCoords(entity)) + + if closestDistance == -1 or distance <= closestDistance then + closestEntity, closestDistance = isPlayerEntity and k or entity, distance + end + end + + return closestEntity, closestDistance +end + +GetClosestEntities = function(isPlayerEntity, coords, distance) + local entites = GetEntities(isPlayerEntity) + local closestEntities = {} + + if coords then + coords = vector3(coords.x, coords.y, coords.z) + else + coords = GetEntityCoords(PlayerPedId()) + end + + for k, entity in pairs(entites) do + local dist = #(coords - GetEntityCoords(entity)) + + if dist <= distance then + closestEntities[#closestEntities + 1] = isPlayerEntity and k or entity + end + end + + return closestEntities +end + +PlayerDied = function(deathCause, killer, killerServerId) + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + + local data = { + killedByPlayer = false, + victim = playerPed, + victimCoords = playerCoords, + victimServerId = GetPlayerServerId(PlayerId()) + } + + if killer and killerServerId then + local killerPed = GetPlayerPed(killer) + local killerCoords = GetEntityCoords(killerPed) + local dist = #(playerCoords - killerCoords) + + data.killedByPlayer = true + data.killer = killerPed + data.killerCoords = killerCoords + data.killerServerId = killerServerId + data.distance = MSK.Math.Round(dist, 2) + end + + TriggerEvent('msk_core:onPlayerDeath', data) + TriggerServerEvent('msk_core:onPlayerDeath', data) +end + +AddEventHandler('gameEventTriggered', function(event, data) + if event == 'CEventNetworkEntityDamage' then + local entity, model = data[1], data[7] + + if IsEntityAPed(entity) and IsPedAPlayer(entity) then + local playerPed = entity + local playerDied = data[4] + + if playerDied and NetworkGetPlayerIndexFromPed(playerPed) == PlayerId() and (IsPedDeadOrDying(playerPed, true) or IsPedFatallyInjured(playerPed)) then + local deathCause, killerEntity = GetPedCauseOfDeath(playerPed), GetPedSourceOfDeath(playerPed) + local killer = NetworkGetPlayerIndexFromPed(killerEntity) + + if killerEntity ~= playerPed and killer and NetworkIsPlayerActive(killer) then + PlayerDied(deathCause, killer, GetPlayerServerId(killer)) + else + PlayerDied(deathCause) + end + end + elseif IsEntityAVehicle(entity) then + local vehicle = entity + + -- Do something with the vehicle... + end + end +end) \ No newline at end of file diff --git a/client/functions/input.lua b/client/functions/input.lua index 64adcd2..902c277 100644 --- a/client/functions/input.lua +++ b/client/functions/input.lua @@ -1,9 +1,10 @@ +MSK.Input = {} + local isInputOpen = false local callback = nil -MSK.Input = function(header, placeholder, field, cb) +MSK.Input.Open = function(header, placeholder, field, cb) if isInputOpen then return end - logging('debug', 'MSK.Input') isInputOpen = true callback = cb if not callback then callback = field end @@ -27,11 +28,17 @@ MSK.Input = function(header, placeholder, field, cb) return result end end -exports('Input', MSK.Input) -exports('openInput', MSK.Input) -- Support for old Scripts +exports('Input', MSK.Input.Open) +exports('openInput', MSK.Input.Open) -- Support for old Scripts + +-- Support for old Scripts +setmetatable(MSK.Input, { + __call = function(_, header, placeholder, field, cb) + return MSK.Input.Open(header, placeholder, field, cb) + end +}) -MSK.CloseInput = function() - logging('debug', 'MSK.CloseInput') +MSK.Input.Close = function() isInputOpen = false callback = nil SetNuiFocus(false, false) @@ -39,26 +46,26 @@ MSK.CloseInput = function() action = 'closeInput' }) end -exports('CloseInput', MSK.CloseInput) -exports('closeInput', MSK.CloseInput) -- Support for old Scripts -RegisterNetEvent('msk_core:closeInput', MSK.CloseInput) +MSK.CloseInput = MSK.Input.Close -- Support for old Scripts +exports('CloseInput', MSK.Input.Close) +RegisterNetEvent('msk_core:closeInput', MSK.Input.Close) MSK.Register('msk_core:input', function(source, header, placeholder, field) - return MSK.Input(header, placeholder, field) + return MSK.Input.Open(header, placeholder, field) end) RegisterNUICallback('submitInput', function(data) if data.input == '' then data.input = nil end if tonumber(data.input) then data.input = tonumber(data.input) end callback(data.input) - MSK.CloseInput() + MSK.Input.Close() end) RegisterNUICallback('closeInput', function(data) - MSK.CloseInput() + MSK.Input.Close() end) AddEventHandler('onResourceStop', function(resource) if GetCurrentResourceName() ~= resource then return end - MSK.CloseInput() + MSK.Input.Close() end) \ No newline at end of file diff --git a/client/functions/main.lua b/client/functions/main.lua index d3dcf5c..34ac6a2 100644 --- a/client/functions/main.lua +++ b/client/functions/main.lua @@ -167,32 +167,6 @@ MSK.HasItem = function(item) end exports('HasItem', MSK.HasItem) -MSK.GetVehicleInDirection = function() - local playerPed = PlayerPedId() - local playerCoords = GetEntityCoords(playerPed) - local inDirection = GetOffsetFromEntityInWorldCoords(playerPed, 0.0, 5.0, 0.0) - local rayHandle = StartExpensiveSynchronousShapeTestLosProbe(playerCoords, inDirection, 10, playerPed, 0) - local numRayHandle, hit, endCoords, surfaceNormal, entityHit = GetShapeTestResult(rayHandle) - - if hit == 1 and GetEntityType(entityHit) == 2 then - local entityCoords = GetEntityCoords(entityHit) - local entityDistance = #(playerCoords - entityCoords) - return entityHit, entityCoords, entityDistance - end - - return nil -end -exports('GetVehicleInDirection', MSK.GetVehicleInDirection) - -MSK.IsVehicleEmpty = function(vehicle) - assert(vehicle and DoesEntityExist(vehicle), 'Parameter "vehicle" is nil or the Vehicle does not exist') - local passengers = GetVehicleNumberOfPassengers(vehicle) - local driverSeatFree = IsVehicleSeatFree(vehicle, -1) - - return passengers == 0 and driverSeatFree -end -exports('IsVehicleEmpty', MSK.IsVehicleEmpty) - MSK.IsSpawnPointClear = function(coords, maxDistance) local nearbyVehicles = {} @@ -214,17 +188,6 @@ MSK.IsSpawnPointClear = function(coords, maxDistance) end exports('IsSpawnPointClear', MSK.IsSpawnPointClear) -MSK.GetPedVehicleSeat = function(ped, vehicle) - if not ped then ped = PlayerPedId() end - if not vehicle then GetVehiclePedIsIn(ped, false) end - - for i = -1, 16 do - if (GetPedInVehicleSeat(vehicle, i) == ped) then return i end - end - return -1 -end -exports('GetPedVehicleSeat', MSK.GetPedVehicleSeat) - MSK.GetPedMugshot = function(ped, transparent) assert(ped and DoesEntityExist(ped), 'Parameter "ped" is nil or the PlayerPed does not exist') local mugshot = transparent and RegisterPedheadshotTransparent(ped) or RegisterPedheadshot(ped) @@ -282,4 +245,14 @@ MSK.LoadModel = function(modelHash) end end end -exports('LoadModel', MSK.LoadModel) \ No newline at end of file +exports('LoadModel', MSK.LoadModel) + +MSK.GetClosestPlayer = function(coords) + return GetClosestEntity(true, coords) +end +exports('GetClosestPlayer', MSK.GetClosestPlayer) + +MSK.GetClosestPlayers = function(coords, distance) + return GetClosestEntities(true, coords, distance) +end +exports('GetClosestPlayers', MSK.GetClosestPlayers) \ No newline at end of file diff --git a/client/functions/numpad.lua b/client/functions/numpad.lua index 14ab1ea..9990853 100644 --- a/client/functions/numpad.lua +++ b/client/functions/numpad.lua @@ -1,9 +1,10 @@ +MSK.Numpad = {} + local isNumpadOpen = false local callback = nil -MSK.Numpad = function(pin, show, cb) +MSK.Numpad.Open = function(pin, show, cb) if isNumpadOpen then return end - logging('debug', 'MSK.Numpad') isNumpadOpen = true callback = cb @@ -28,10 +29,17 @@ MSK.Numpad = function(pin, show, cb) return result end end -exports('Numpad', MSK.Numpad) +exports('Numpad', MSK.Numpad.Open) + +-- Support for old Scripts +setmetatable(MSK.Numpad, { + __call = function(_, pin, show, cb) + -- Ruft MSK.Numpad.Open auf, wenn MSK.Numpad() aufgerufen wird + return MSK.Numpad.Open(pin, show, cb) + end +}) -MSK.CloseNumpad = function() - logging('debug', 'MSK.CloseNumpad') +MSK.Numpad.Close = function() isNumpadOpen = false callback = nil SetNuiFocus(false, false) @@ -39,24 +47,25 @@ MSK.CloseNumpad = function() action = 'closeNumpad' }) end -exports('CloseNumpad', MSK.CloseNumpad) -RegisterNetEvent('msk_core:closeNumpad', MSK.CloseNumpad) +MSK.CloseNumpad = MSK.Numpad.Close +exports('CloseNumpad', MSK.Numpad.Close) +RegisterNetEvent('msk_core:closeNumpad', MSK.Numpad.Close) MSK.Register('msk_core:numpad', function(source, pin, show) - return MSK.Numpad(pin, show) + return MSK.Numpad.Open(pin, show) end) RegisterNUICallback('submitNumpad', function(data) callback(true) - MSK.CloseNumpad() + MSK.Numpad.Close() end) RegisterNUICallback('closeNumpad', function() - MSK.CloseNumpad() + MSK.Numpad.Close() end) AddEventHandler('onResourceStop', function(resource) if GetCurrentResourceName() ~= resource then return end - MSK.CloseNumpad() + MSK.Numpad.Close() end) \ No newline at end of file diff --git a/client/functions/showCoords.lua b/client/functions/showCoords.lua index 1d676dd..ecf1e26 100644 --- a/client/functions/showCoords.lua +++ b/client/functions/showCoords.lua @@ -1,19 +1,32 @@ -local showCoords = false +MSK.Coords = {} -MSK.ShowCoords = function() - showCoords = not showCoords +local showCoords = false +MSK.Coords.Show = function() if showCoords then - CreateThread(startShowCoordsThread) + showCoords = false + return end + + showCoords = true + CreateThread(startShowCoordsThread) end -exports('ShowCoords', MSK.ShowCoords) -RegisterNetEvent('msk_core:showCoords', MSK.ShowCoords) +MSK.ShowCoords = MSK.Coords.Show -- Support for old Scripts +exports('ShowCoords', MSK.Coords.Show) +RegisterNetEvent('msk_core:showCoords', MSK.Coords.Show) -MSK.DoesShowCoords = function() +MSK.Coords.Active = function() return showCoords end -exports('DoesShowCoords', MSK.DoesShowCoords) +MSK.DoesShowCoords = MSK.Coords.Active -- Support for old Scripts +exports('CoordsActive', MSK.Coords.Active) +exports('DoesShowCoords', MSK.Coords.Active) -- Support for old Scripts + +MSK.Coords.Hide = function() + showCoords = false +end +exports('HideCoords', MSK.Coords.Hide) +RegisterNetEvent('msk_core:hideCoords', MSK.Coords.Hide) MSK.Register('msk_core:doesShowCoords', function(source) return showCoords @@ -39,7 +52,7 @@ startShowCoordsThread = function() local playerX, playerY, playerZ = table.unpack(GetEntityCoords(playerPed)) local playerH = GetEntityHeading(playerPed) - DrawGenericText(("~g~X~w~ = ~r~%s ~g~Y~w~ = ~r~%s ~g~Z~w~ = ~r~%s ~g~H~w~ = ~r~%s~s~"):format(MSK.Round(playerX, 2), MSK.Round(playerY, 2), MSK.Round(playerZ, 2), MSK.Round(playerH, 2))) + DrawGenericText(("~g~X~w~ = ~r~%s ~g~Y~w~ = ~r~%s ~g~Z~w~ = ~r~%s ~g~H~w~ = ~r~%s~s~"):format(MSK.Math.Round(playerX, 2), MSK.Math.Round(playerY, 2), MSK.Math.Round(playerZ, 2), MSK.Math.Round(playerH, 2))) Wait(sleep) end diff --git a/client/functions/vehicle.lua b/client/functions/vehicle.lua new file mode 100644 index 0000000..4ade039 --- /dev/null +++ b/client/functions/vehicle.lua @@ -0,0 +1,157 @@ +MSK.GetClosestVehicle = function(coords) + return GetClosestEntity(false, coords) +end +exports('GetClosestVehicle', MSK.GetClosestVehicle) + +MSK.GetClosestVehicles = function(coords, distance) + return GetClosestEntities(false, coords, distance) +end +exports('GetClosestVehicles', MSK.GetClosestVehicles) + +MSK.GetVehicleWithPlate = function(plate, coords, distance) + local vehicles = GetClosestEntities(false, coords, distance) + plate = MSK.String.Trim(plate) + + for i=1, #vehicles do + if DoesEntityExist(vehicles[i]) then + if MSK.String.Trim(GetVehicleNumberPlateText(vehicles[i])) == plate and #(coords - GetEntityCoords(vehicles[i])) <= distance then + return vehicles[i] + end + end + end + return false +end +exports('GetVehicleWithPlate', MSK.GetVehicleWithPlate) + +MSK.GetVehicleInDirection = function() + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + local inDirection = GetOffsetFromEntityInWorldCoords(playerPed, 0.0, 5.0, 0.0) + local rayHandle = StartExpensiveSynchronousShapeTestLosProbe(playerCoords, inDirection, 10, playerPed, 0) + local numRayHandle, hit, endCoords, surfaceNormal, entityHit = GetShapeTestResult(rayHandle) + + if hit == 1 and GetEntityType(entityHit) == 2 then + local entityCoords = GetEntityCoords(entityHit) + local entityDistance = #(playerCoords - entityCoords) + return entityHit, entityCoords, entityDistance + end + + return nil +end +exports('GetVehicleInDirection', MSK.GetVehicleInDirection) + +MSK.GetPedVehicleSeat = function(ped, vehicle) + if not ped then ped = PlayerPedId() end + if not vehicle then GetVehiclePedIsIn(ped, false) end + + for i = -1, 16 do + if (GetPedInVehicleSeat(vehicle, i) == ped) then return i end + end + return -1 +end +exports('GetPedVehicleSeat', MSK.GetPedVehicleSeat) + +MSK.IsVehicleEmpty = function(vehicle) + assert(vehicle and DoesEntityExist(vehicle), 'Parameter "vehicle" is nil or the Vehicle does not exist') + local passengers = GetVehicleNumberOfPassengers(vehicle) + local driverSeatFree = IsVehicleSeatFree(vehicle, -1) + + return passengers == 0 and driverSeatFree +end +exports('IsVehicleEmpty', MSK.IsVehicleEmpty) + +MSK.GetVehicleLabel = function(vehicle) + assert(vehicle and DoesEntityExist(vehicle), 'Parameter "vehicle" is nil or the Vehicle does not exist on function MSK.GetVehicleLabel') + local vehicleModel = GetEntityModel(vehicle) + local vehicleLabel = GetDisplayNameFromVehicleModel(vehicleModel):lower() + + if not vehicleLabel or vehicleLabel == 'null' or vehicleLabel == 'carnotfound' then + vehicleLabel = 'Unknown' + else + local labelText = GetLabelText(vehicleLabel) + + if labelText:lower() ~= 'null' then + vehicleLabel = labelText + end + end + + return vehicleLabel +end +exports('GetVehicleLabel', MSK.GetVehicleLabel) + +MSK.GetVehicleLabelFromModel = function(model) + assert(model and IsModelValid(model), 'Parameter "model" is nil or the Model does not exist on function MSK.GetVehicleLabelFromModel') + local vehicleLabel = GetDisplayNameFromVehicleModel(model):lower() + + if not vehicleLabel or vehicleLabel == 'null' or vehicleLabel == 'carnotfound' then + vehicleLabel = 'Unknown' + else + local labelText = GetLabelText(vehicleLabel) + + if labelText:lower() ~= 'null' then + vehicleLabel = labelText + end + end + + return vehicleLabel +end +exports('GetVehicleLabelFromModel', MSK.GetVehicleLabelFromModel) + +MSK.CloseVehicleDoors = function(vehicle) + assert(vehicle and DoesEntityExist(vehicle), 'Parameter "vehicle" is nil or the Vehicle does not exist on function MSK.CloseVehicleDoors') + + for doorIndex = 0, 7 do + if (DoesVehicleHaveDoor(vehicle, doorIndex) and GetVehicleDoorAngleRatio(vehicle, doorIndex) > 0) then + SetVehicleDoorShut(vehicle, doorIndex, false) + end + end +end +exports('CloseVehicleDoors', MSK.CloseVehicleDoors) + +-- Credits to ESX Legacy (https://github.com/esx-framework/esx_core/blob/main/[core]/es_extended/client/modules/actions.lua) +local currentVehicle = {} +local isInVehicle, isEnteringVehicle = false, false +CreateThread(function() + while true do + local sleep = 200 + local playerPed = PlayerPedId() + + if not isInVehicle and not IsPlayerDead(PlayerId()) then + if DoesEntityExist(GetVehiclePedIsTryingToEnter(playerPed)) and not isEnteringVehicle then + local vehicle = GetVehiclePedIsTryingToEnter(playerPed) + local plate = GetVehicleNumberPlateText(vehicle) + local seat = GetSeatPedIsTryingToEnter(playerPed) + local netId = VehToNet(vehicle) + local isEngineOn = Entity(vehicle).state.isEngineOn or GetIsVehicleEngineRunning(vehicle) + local isDamaged = Entity(vehicle).state.isDamaged or false + isEnteringVehicle = true + TriggerEvent('msk_core:enteringVehicle', vehicle, plate, seat, netId, isEngineOn, isDamaged) + TriggerServerEvent('msk_core:enteringVehicle', plate, seat, netId, isEngineOn, isDamaged) + elseif not DoesEntityExist(GetVehiclePedIsTryingToEnter(playerPed)) and not IsPedInAnyVehicle(playerPed, true) and isEnteringVehicle then + TriggerEvent('msk_core:enteringVehicleAborted') + TriggerServerEvent('msk_core:enteringVehicleAborted') + isEnteringVehicle = false + elseif IsPedInAnyVehicle(playerPed, false) then + isEnteringVehicle = false + isInVehicle = true + currentVehicle.vehicle = GetVehiclePedIsIn(playerPed) + currentVehicle.plate = GetVehicleNumberPlateText(currentVehicle.vehicle) + currentVehicle.seat = MSK.GetPedVehicleSeat(playerPed, currentVehicle.vehicle) + currentVehicle.netId = VehToNet(currentVehicle.vehicle) + currentVehicle.isEngineOn = Entity(currentVehicle.vehicle).state.isEngineOn or GetIsVehicleEngineRunning(currentVehicle.vehicle) + currentVehicle.isDamaged = Entity(currentVehicle.vehicle).state.isDamaged or false + TriggerEvent('msk_core:enteredVehicle', currentVehicle.vehicle, currentVehicle.plate, currentVehicle.seat, currentVehicle.netId, currentVehicle.isEngineOn, currentVehicle.isDamaged) + TriggerServerEvent('msk_core:enteredVehicle', currentVehicle.plate, currentVehicle.seat, currentVehicle.netId, currentVehicle.isEngineOn, currentVehicle.isDamaged) + end + elseif isInVehicle then + if not IsPedInAnyVehicle(playerPed, false) or IsPlayerDead(PlayerId()) then + isInVehicle = false + TriggerEvent('msk_core:exitedVehicle', currentVehicle.vehicle, currentVehicle.plate, currentVehicle.seat, currentVehicle.netId, currentVehicle.isEngineOn, currentVehicle.isDamaged) + TriggerServerEvent('msk_core:exitedVehicle', currentVehicle.plate, currentVehicle.seat, currentVehicle.netId, currentVehicle.isEngineOn, currentVehicle.isDamaged) + currentVehicle = {} + end + end + + Wait(sleep) + end +end) \ No newline at end of file diff --git a/client/main.lua b/client/main.lua index fd250d5..347dd1e 100644 --- a/client/main.lua +++ b/client/main.lua @@ -57,11 +57,6 @@ if MSK.Bridge.Framework.Type == 'ESX' then RegisterNetEvent('esx:setJob', function(newJob, lastJob) TriggerEvent(MSK.Bridge.Framework.Events.setJob, MSK.Bridge.Player, newJob, lastJob) end) - - RegisterNetEvent('esx:onPlayerDeath', function() - TriggerEvent(MSK.Bridge.Framework.Events.onPlayerDeath, MSK.Bridge.Player) - TriggerServerEvent(MSK.Bridge.Framework.Events.onPlayerDeath) - end) elseif MSK.Bridge.Framework.Type == 'QBCore' then RegisterNetEvent('QBCore:Player:SetPlayerData', function(PlayerData) TriggerEvent(MSK.Bridge.Framework.Events.setPlayerData, MSK.Bridge.Player) @@ -84,11 +79,6 @@ elseif MSK.Bridge.Framework.Type == 'QBCore' then TriggerEvent(MSK.Bridge.Framework.Events.setJob, MSK.Bridge.Player, newJob) TriggerServerEvent(MSK.Bridge.Framework.Events.playerLogout, newJob) end) - - RegisterNetEvent('QBCore:Client:OnPlayerDeath', function() - TriggerEvent(MSK.Bridge.Framework.Events.onPlayerDeath, MSK.Bridge.Player) - TriggerServerEvent(MSK.Bridge.Framework.Events.onPlayerDeath) - end) end GetLib = function() diff --git a/fxmanifest.lua b/fxmanifest.lua index 546b9f9..d8889ff 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -4,7 +4,7 @@ games { 'gta5' } author 'Musiker15 - MSK Scripts' name 'msk_core' description 'Functions for MSK Scripts' -version '2.4.6' +version '2.4.7' lua54 'yes' @@ -14,7 +14,7 @@ shared_scripts { client_scripts { 'client/main.lua', - 'shared/*.lua', + 'shared/**/*.*', 'client/functions/*.lua', 'client/bridge/*.lua', } @@ -22,7 +22,7 @@ client_scripts { server_scripts { '@oxmysql/lib/MySQL.lua', 'server/main.lua', - 'shared/*.lua', + 'shared/**/*.*', 'server/versionchecker.lua', 'server/functions/*.lua', 'server/inventories/*.lua', diff --git a/html/css/notify.css b/html/css/notify.css index 967c9c0..0171c2b 100644 --- a/html/css/notify.css +++ b/html/css/notify.css @@ -20,7 +20,7 @@ rgba(56, 56, 56, 0.4), 1.0vh, rgba(56, 56, 56, 0.4) 2.0vh ); - background-color:rgba(0, 0, 0, 0); + background-color: rgb(0, 0, 0); border-radius:0.6vh; box-shadow:0vh 0vh 2vh 0vh rgba(0, 0, 0, 0.8) inset; } diff --git a/server/functions/bansystem.lua b/server/functions/bansystem.lua index cf5ad7d..7e8521a 100644 --- a/server/functions/bansystem.lua +++ b/server/functions/bansystem.lua @@ -130,7 +130,7 @@ MSK.IsPlayerBanned = function(playerId) player.name = GetPlayerName(playerId) for _, v in pairs(identifiers) do - player[MSK.Split(v, ':')[1]] = v + player[MSK.String.Split(v, ':')[1]] = v end for i = 1, #bannedPlayers do @@ -168,7 +168,7 @@ MSK.BanPlayer = function(playerId, targetId, time, reason) player.name = targetName for k, v in pairs(identifiers) do - player[MSK.Split(v, ':')[1]] = v + player[MSK.String.Split(v, ':')[1]] = v end local num = GetNumPlayerTokens(targetId) diff --git a/server/functions/cronjobs.lua b/server/functions/cronjobs.lua index a0de67c..6363ba2 100644 --- a/server/functions/cronjobs.lua +++ b/server/functions/cronjobs.lua @@ -1,3 +1,5 @@ +MSK.Cron = {} + local CronJobs, CronJobsAt = {}, {} local CronJobUniqueIds = {} @@ -39,7 +41,7 @@ tickCronJob = function() local currH = tonumber(os.date('%H', currTime)) local currM = tonumber(os.date('%M', currTime)) - for i=1, #CronJobs, 1 do + for i=1, #CronJobs do local timestamp = CronJobs[i].timestamp local d = tonumber(os.date('%d', timestamp)) local h = tonumber(os.date('%H', timestamp)) @@ -61,7 +63,7 @@ tickCronJobAt = function() local currH = tonumber(os.date('%H', currTime)) local currM = tonumber(os.date('%M', currTime)) - for i=1, #CronJobsAt, 1 do + for i=1, #CronJobsAt do if (not CronJobsAt[i].date.atD or CronJobsAt[i].date.atD and currD == CronJobsAt[i].date.atD) and currH == CronJobsAt[i].date.atH and currM == CronJobsAt[i].date.atM then CronJobsAt[i].cb(CronJobs[i].id, CronJobsAt[i].data, {timestamp = currTime, d = currD, h = currH, m = currM}) end @@ -71,7 +73,7 @@ tickCronJobAt = function() end tickCronJobAt() -MSK.CreateCron = function(date, data, cb) +MSK.Cron.Create = function(date, data, cb) local currTime = os.time() local timestamp = date @@ -81,11 +83,11 @@ MSK.CreateCron = function(date, data, cb) if currTime == timestamp then if date.atH and date.atH > 23 then - return print('[^1ERROR^0]', 'Value "atH" can\'t be greater than 23 on MSK.CreateCron') + return print('[^1ERROR^0]', 'Value "atH" can\'t be greater than 23 on MSK.Cron.Create') end if date.atM and date.atM > 59 then - return print('[^1ERROR^0]', 'Value "atM" can\'t be greater than 59 on MSK.CreateCron') + return print('[^1ERROR^0]', 'Value "atM" can\'t be greater than 59 on MSK.Cron.Create') end CronJobsAt[#CronJobsAt + 1] = { @@ -108,15 +110,16 @@ MSK.CreateCron = function(date, data, cb) logging('debug', 'Created CronJob at: ' .. os.date('%d.%m.%Y %H:%M:%S', os.time()), 'Will be executed at: ' .. os.date('%d.%m.%Y %H:%M:%S', CronJobs[#CronJobs].timestamp)) end end -exports('CreateCron', MSK.CreateCron) -RegisterNetEvent('msk_core:createCron', MSK.CreateCron) +MSK.CreateCron = MSK.Cron.Create +exports('CreateCron', MSK.Cron.Create) +RegisterNetEvent('msk_core:createCron', MSK.Cron.Create) -MSK.DeleteCron = function(id) +MSK.Cron.Delete = function(id) if not id then return end if not CronJobUniqueIds[id] then return end local found = false - for i=1, #CronJobs, 1 do + for i=1, #CronJobs do if CronJobs[i].uniqueId == id then CronJobs[i] = nil CronJobUniqueIds[id] = nil @@ -127,7 +130,7 @@ MSK.DeleteCron = function(id) if found then return found end - for i=1, #CronJobsAt, 1 do + for i=1, #CronJobsAt do if CronJobsAt[i].uniqueId == id then CronJobsAt[i] = nil CronJobUniqueIds[id] = nil @@ -138,4 +141,5 @@ MSK.DeleteCron = function(id) return found end -exports('DeleteCron', MSK.DeleteCron) \ No newline at end of file +MSK.DeleteCron = MSK.Cron.Delete +exports('DeleteCron', MSK.Cron.Delete) \ No newline at end of file diff --git a/server/functions/disconnectlogger.lua b/server/functions/disconnectlogger.lua index a811003..8748520 100644 --- a/server/functions/disconnectlogger.lua +++ b/server/functions/disconnectlogger.lua @@ -8,7 +8,7 @@ AddEventHandler('playerDropped', function(reason) local coords = GetEntityCoords(GetPlayerPed(src)) local time = os.date('%d.%m.%Y %H:%M', os.time()) - TriggerClientEvent('msk_core:anticombatlog', -1, { + TriggerClientEvent('msk_core:discLogger', -1, { playerId = src, playerName = playerName, coords = coords, diff --git a/server/functions/entities.lua b/server/functions/entities.lua new file mode 100644 index 0000000..0d63b64 --- /dev/null +++ b/server/functions/entities.lua @@ -0,0 +1,59 @@ +GetEntities = function(isPlayerEntity) + local entities = {} + + if isPlayerEntity then + for _, playerId in ipairs(GetPlayers()) do + local ped = GetPlayerPed(playerId) + + if DoesEntityExist(ped) then + entities[playerId] = ped + end + end + else + entities = GetAllVehicles() + end + + return entities +end + +GetClosestEntity = function(isPlayerEntity, coords) + local closestEntity, closestDistance = -1, -1 + local entites = GetEntities(isPlayerEntity) + + if coords then + coords = vector3(coords.x, coords.y, coords.z) + else + coords = GetEntityCoords(GetPlayerPed(isPlayerEntity)) + end + + for k, entity in pairs(entites) do + local distance = #(coords - GetEntityCoords(entity)) + + if closestDistance == -1 or distance <= closestDistance and (not isPlayerEntity or isPlayerEntity and entity ~= GetPlayerPed(isPlayerEntity)) then + closestEntity, closestDistance = isPlayerEntity and k or entity, distance + end + end + + return closestEntity, closestDistance +end + +GetClosestEntities = function(isPlayerEntity, coords, distance) + local entites = GetEntities(isPlayerEntity) + local closestEntities = {} + + if coords then + coords = vector3(coords.x, coords.y, coords.z) + else + coords = GetEntityCoords(GetPlayerPed(isPlayerEntity)) + end + + for k, entity in pairs(entites) do + local dist = #(coords - GetEntityCoords(entity)) + + if dist <= distance and (not isPlayerEntity or isPlayerEntity and entity ~= GetPlayerPed(isPlayerEntity)) then + closestEntities[#closestEntities + 1] = isPlayerEntity and k or entity + end + end + + return closestEntities +end \ No newline at end of file diff --git a/server/functions/main.lua b/server/functions/main.lua index f2f2388..45dd999 100644 --- a/server/functions/main.lua +++ b/server/functions/main.lua @@ -105,16 +105,15 @@ MSK.IsSpawnPointClear = function(coords, maxDistance) end exports('IsSpawnPointClear', MSK.IsSpawnPointClear) -MSK.GetPedVehicleSeat = function(ped, vehicle) - if not ped then return end - if not vehicle then GetVehiclePedIsIn(ped, false) end - - for i = -1, 16 do - if (GetPedInVehicleSeat(vehicle, i) == ped) then return i end - end - return -1 +MSK.GetClosestPlayer = function(playerId, coords) + return GetClosestEntity(playerId, coords) +end +exports('GetClosestPlayer', MSK.GetClosestPlayer) + +MSK.GetClosestPlayers = function(playerId, coords, distance) + return GetClosestEntities(playerId, coords, distance) end -exports('GetPedVehicleSeat', MSK.GetPedVehicleSeat) +exports('GetClosestPlayers', MSK.GetClosestPlayers) MSK.AddWebhook = function(webhook, botColor, botName, botAvatar, title, description, fields, footer, time) local content = {} @@ -186,12 +185,10 @@ MSK.RegisterCommand = function(name, group, cb, console, framework, suggestion) end if RegisteredCommands[name] then - logging('debug', ('Command ^3%s^0 is already registerd. Overriding Command...'):format(name)) + logging('info', ('Command ^3%s^0 is already registerd. Overriding Command...'):format(name)) end - local added = addChatSuggestions(name, suggestion) - while not added do Wait(1) end - + addChatSuggestions(name, suggestion) RegisteredCommands[name] = {group = group, cb = cb, console = console, suggestion = suggestion} RegisterCommand(name, function(source, args, rawCommand) @@ -201,40 +198,73 @@ MSK.RegisterCommand = function(name, group, cb, console, framework, suggestion) if not Command.console and source == 0 then logging('error', 'You can not run this Command in Server Console!') else - if Command.suggestion and Command.suggestion.arguments then - local newArgs = {} + if Command.suggestion then + if Command.suggestion.validate or Command.suggestion.val then + if not Command.suggestion.arguments or #args ~= #Command.suggestion.arguments then + error = ('Invalid Argument Count (passed %s, wanted %s)'):format(#args, #Command.suggestion.arguments) + end + end - for k, v in ipairs(Command.suggestion.arguments) do - if v.action == 'number' then - if args[k] then - if tonumber(args[k]) then - newArgs[v.name] = args[k] + if not error and Command.suggestion.arguments then + local newArgs = {} + + for k, v in ipairs(Command.suggestion.arguments) do + local action = v.action or v.type + + if action then + if action == 'number' then + local newArg = tonumber(args[k]) + + if newArg then + newArgs[v.name] = newArg + else + error = ('Invalid Argument %s data type (passed string, wanted number)'):format(v.name) + end + elseif action == 'string' then + local newArg = tonumber(args[k]) + + if not newArg then + newArgs[v.name] = args[k] + else + error = ('Invalid Argument %s data type (passed number, wanted string)'):format(v.name) + end + elseif action == 'playerId' or action == 'player' then + local targetId = tonumber(targetId) + if args[k] == 'me' then targetId = source end + + if targetId and doesPlayerIdExist(targetId) then + if action == 'player' then + if (MSK.Bridge.Framework.Type == 'ESX' or MSK.Bridge.Framework.Type == 'QBCore') then + local Player = MSK.GetPlayer({source = targetId}) + + if Player then + newArgs[v.name] = Player + else + error = ('Specified Player (ID: %s) is not online'):format(targetId) + end + else + error = ('Specified Player not found on Argument %s (Framework not compatible)'):format(v.name) + end + else + newArgs[v.name] = targetId + end + else + error = ('Specified PlayerId %s is not online'):format(targetId) + end else - error = ('Argument %s is not a number!'):format(v.name) + newArgs[v.name] = args[k] end end - elseif v.action == 'playerId' then - if args[k] then - local targetId = args[k] - if targetId == 'me' then targetId = source end - if tonumber(targetId) > 0 and doesPlayerIdExist(targetId) then - newArgs[v.name] = targetId - else - error = ('PlayerId %s does not exist!'):format(targetId) - end + -- Backwards compatibility + if not error and not newArgs[v.name] and v.val then + error = ('Invalid Argument Count (passed %s, wanted %s)'):format(#args, #Command.suggestion.arguments) end - else - newArgs[v.name] = args[k] + if error then break end end - if not error and not newArgs[v.name] and v.val then - error = ('Argument Mismatch with Argument %s'):format(v.name) - end - if error then break end + args = newArgs end - - args = newArgs end if error then @@ -244,7 +274,7 @@ MSK.RegisterCommand = function(name, group, cb, console, framework, suggestion) MSK.Notification(source, error) end else - if Config.Framework ~= 'Standalone' and framework then + if framework and (MSK.Bridge.Framework.Type == 'ESX' or MSK.Bridge.Framework.Type == 'QBCore') then local Player = MSK.GetPlayer({source = source}) cb(Player, args, rawCommand) else @@ -286,6 +316,4 @@ addChatSuggestions = function(name, suggestion) TriggerClientEvent('chat:addSuggestion', -1, '/' .. name, suggestion.help, suggestion.arguments) end - - return true end \ No newline at end of file diff --git a/server/functions/showCoords.lua b/server/functions/showCoords.lua index fbc4aed..c89aa1c 100644 --- a/server/functions/showCoords.lua +++ b/server/functions/showCoords.lua @@ -1,16 +1,27 @@ +MSK.Coords = {} + if Config.showCoords.enable then MSK.RegisterCommand(Config.showCoords.command, Config.showCoords.groups, function(source, args, rawCommand) - MSK.ShowCoords(source) + MSK.Coords.Show(source) end, false --[[console]], false --[[framework]], {help = 'Show your own Coords'}) end -MSK.ShowCoords = function(src) - TriggerClientEvent('msk_core:showCoords', src) +MSK.Coords.Show = function(playerId) + if not playerId or playerId == 0 then return end + TriggerClientEvent('msk_core:showCoords', playerId) +end +MSK.ShowCoords = MSK.Coords.Show -- Support for old Scripts +exports('ShowCoords', MSK.Coords.Show) + +MSK.Coords.Active = function(playerId) + if not playerId or playerId == 0 then return end + return MSK.Trigger('msk_core:doesShowCoords', playerId) end -exports('ShowCoords', MSK.ShowCoords) +MSK.DoesShowCoords = MSK.Coords.Active -- Support for old Scripts +exports('DoesShowCoords', MSK.Coords.Active) -MSK.DoesShowCoords = function(src) - if not src or src == 0 then return end - return MSK.Trigger('msk_core:doesShowCoords', src) +MSK.Coords.Hide = function(playerId) + if not playerId or playerId == 0 then return end + TriggerClientEvent('msk_core:hideCoords', playerId) end -exports('DoesShowCoords', MSK.DoesShowCoords) \ No newline at end of file +exports('HideCoords', MSK.Coords.Hide) \ No newline at end of file diff --git a/server/functions/vehicle.lua b/server/functions/vehicle.lua new file mode 100644 index 0000000..6c2b106 --- /dev/null +++ b/server/functions/vehicle.lua @@ -0,0 +1,35 @@ +MSK.GetClosestVehicle = function(coords) + return GetClosestEntity(false, coords) +end +exports('GetClosestVehicle', MSK.GetClosestVehicle) + +MSK.GetClosestVehicles = function(coords, distance) + return GetClosestEntities(false, coords, distance) +end +exports('GetClosestVehicles', MSK.GetClosestVehicles) + +MSK.GetVehicleWithPlate = function(plate, coords, distance) + local vehicles = GetClosestEntities(false, coords, distance) + plate = MSK.String.Trim(plate) + + for i=1, #vehicles do + if DoesEntityExist(vehicles[i]) then + if MSK.String.Trim(GetVehicleNumberPlateText(vehicles[i])) == plate and #(coords - GetEntityCoords(vehicles[i])) <= distance then + return vehicles[i] + end + end + end + return false +end +exports('GetVehicleWithPlate', MSK.GetVehicleWithPlate) + +MSK.GetPedVehicleSeat = function(ped, vehicle) + if not ped then return end + if not vehicle then GetVehiclePedIsIn(ped, false) end + + for i = -1, 16 do + if (GetPedInVehicleSeat(vehicle, i) == ped) then return i end + end + return -1 +end +exports('GetPedVehicleSeat', MSK.GetPedVehicleSeat) \ No newline at end of file diff --git a/server/inventories/ox_inventory.lua b/server/inventories/ox_inventory.lua index fb5a753..164d10e 100644 --- a/server/inventories/ox_inventory.lua +++ b/server/inventories/ox_inventory.lua @@ -31,7 +31,7 @@ FunctionOverride = function(Player) end Player.AddWeapon = function(weapon, count, metadata, slot) - exports.ox_inventory:AddItem(playerId, weapon, count or 1, metadata, slot) + exports.ox_inventory:AddItem(playerId, weapon, 1, metadata or {ammo = count}, slot) end Player.RemoveWeapon = function(weapon, count, metadata, slot) diff --git a/server/main.lua b/server/main.lua index 8a42d55..4df657e 100644 --- a/server/main.lua +++ b/server/main.lua @@ -13,13 +13,12 @@ if Config.Framework == 'AUTO' then ESX = exports["es_extended"]:getSharedObject() MSK.Bridge.Framework.Type = 'ESX' MSK.Bridge.Framework.Core = ESX - print(('[^2%s^0] [^4Info^0] Framework ^3ESX^0 found'):format(GetCurrentResourceName())) elseif GetResourceState('qb-core') ~= 'missing' then QBCore = exports['qb-core']:GetCoreObject() MSK.Bridge.Framework.Type = 'QBCore' MSK.Bridge.Framework.Core = QBCore - print(('[^2%s^0] [^4Info^0] Framework ^3QBCore^0 found'):format(GetCurrentResourceName())) end + print(('[^2%s^0] [^4Info^0] Framework ^3%s^0 found'):format(GetCurrentResourceName(), MSK.Bridge.Framework.Type)) elseif Config.Framework == 'ESX' then ESX = exports["es_extended"]:getSharedObject() MSK.Bridge.Framework.Type = 'ESX' diff --git a/server/versionchecker.lua b/server/versionchecker.lua index 0dcc934..a33a357 100644 --- a/server/versionchecker.lua +++ b/server/versionchecker.lua @@ -39,8 +39,8 @@ local CheckVersionCallback = function(status, response, header) return end - local current = MSK.Split(currentVersion, '.') - local latest = MSK.Split(latestVersion, '.') + local current = MSK.String.Split(currentVersion, '.') + local latest = MSK.String.Split(latestVersion, '.') for i = 1, #current do if current[i] > latest[i] then diff --git a/shared/functions.lua b/shared/functions.lua new file mode 100644 index 0000000..035b5c3 --- /dev/null +++ b/shared/functions.lua @@ -0,0 +1,47 @@ +MSK.GetConfig = function() + return Config +end +exports('GetConfig', MSK.GetConfig) + +local Timeouts = {} +local TimeoutId = 0 +MSK.SetTimeout = function(ms, cb, data) + assert(ms and tonumber(ms), 'Parameter "ms" has to be a number on function MSK.SetTimeout') + local requestId = TimeoutId + 1 + + SetTimeout(ms, function() + if Timeouts[requestId] then + Timeouts[requestId] = nil + return + end + + cb(data) + end) + + TimeoutId = requestId + + return requestId +end +MSK.AddTimeout = MSK.SetTimeout -- Support for old Versions +exports('SetTimeout', MSK.SetTimeout) + +MSK.ClearTimeout = function(requestId) + assert(requestId, 'Parameter "requestId" is nil on function MSK.ClearTimeout') + Timeouts[requestId] = true +end +MSK.DelTimeout = MSK.ClearTimeout -- Support for old Versions +exports('DelTimeout', MSK.ClearTimeout) -- Support for old Versions +exports('ClearTimeout', MSK.ClearTimeout) + +MSK.Logging = function(code, ...) + assert(code and type(code) == 'string', 'Parameter "code" has to be a string on function MSK.Logging') + local script = ('[^2%s^0]'):format(GetInvokingResource() or 'msk_core') + print(('%s %s'):format(script, Config.LoggingTypes[code] or Config.LoggingTypes['debug']), ...) +end +MSK.logging = MSK.Logging -- Support for old Versions +exports('Logging', MSK.Logging) + +logging = function(code, ...) + if not Config.Debug and code == 'debug' then return end + MSK.Logging(code, ...) +end \ No newline at end of file diff --git a/shared/math.lua b/shared/math.lua new file mode 100644 index 0000000..d54662a --- /dev/null +++ b/shared/math.lua @@ -0,0 +1,40 @@ +MSK.Math = {} +local Numbers = {} + +for i = 48, 57 do table.insert(Numbers, string.char(i)) end + +MSK.Math.Number = function(length) + assert(length, 'Parameter "length" is nil on function MSK.Math.Number') + math.randomseed(GetGameTimer()) + + return length > 0 and MSK.Math.Number(length - 1) .. Numbers[math.random(1, #Numbers)] or '' +end +MSK.GetRandomNumber = MSK.Math.Number +exports('GetRandomNumber', MSK.Math.Number) + +MSK.Math.Round = function(num, decimal) + assert(num and tonumber(num), 'Parameter "num" has to be a number on function MSK.Math.Round') + assert(not decimal or decimal and tonumber(decimal), 'Parameter "decimal" has to be a number on function MSK.Math.Round') + return tonumber(string.format("%." .. (decimal or 0) .. "f", num)) +end +MSK.Round = MSK.Math.Round +exports('Round', MSK.Math.Round) + +MSK.Math.Comma = function(int, tag) + assert(int and tonumber(int), 'Parameter "int" has to be a number on function MSK.Math.Comma') + assert(not tag or tag and type(tag) == 'string' and not tonumber(tag), 'Parameter "tag" has to be a string on function MSK.Math.Comma') + if not tag then tag = '.' end + local newInt = int + + while true do + newInt, k = string.gsub(newInt, "^(-?%d+)(%d%d%d)", '%1'..tag..'%2') + + if (k == 0) then + break + end + end + + return newInt +end +MSK.Comma = MSK.Math.Comma +exports('Comma', MSK.Math.Comma) \ No newline at end of file diff --git a/shared/string.lua b/shared/string.lua new file mode 100644 index 0000000..350382b --- /dev/null +++ b/shared/string.lua @@ -0,0 +1,51 @@ +MSK.String = {} +local Charset = {} + +for i = 65, 90 do table.insert(Charset, string.char(i)) end +for i = 97, 122 do table.insert(Charset, string.char(i)) end + +MSK.String.Random = function(length) + assert(length, 'Parameter "length" is nil on function MSK.String.Random') + math.randomseed(GetGameTimer()) + + return length > 0 and MSK.String.Random(length - 1) .. Charset[math.random(1, #Charset)] or '' +end +MSK.GetRandomString = MSK.String.Random +MSK.GetRandomLetter = MSK.String.Random -- Support for old Versions +exports('GetRandomString', MSK.String.Random) + +MSK.String.StartsWith = function(str, startStr) + assert(str and type(str) == 'string', 'Parameter "str" has to be a string on function MSK.String.StartsWith') + assert(startStr and type(startStr) == 'string', 'Parameter "startStr" has to be a string on function MSK.String.StartsWith') + return str:sub(1, #startStr) == startStr +end +MSK.StartsWith = MSK.String.StartsWith +exports('StartsWith', MSK.String.StartsWith) + +MSK.String.Trim = function(str, bool) + assert(str and tostring(str), 'Parameter "str" has to be a string on function MSK.String.Trim') + str = tostring(str) + if bool then return str:gsub("%s+", "") end + return str:gsub("^%s*(.-)%s*$", "%1") +end +exports('Trim', MSK.String.Trim) + +-- Support for old Versions +MSK.Trim = function(str, bool) + if bool then return MSK.String.Trim(str) end + return MSK.String.Trim(str, true) +end + +MSK.String.Split = function(str, delimiter) + assert(str and type(str) == 'string', 'Parameter "str" has to be a string on function MSK.String.Split') + assert(delimiter and type(delimiter) == 'string', 'Parameter "delimiter" has to be a string on function MSK.String.Split') + local result = {} + + for match in str:gmatch("([^"..delimiter.."]+)") do + result[#result + 1] = match + end + + return result +end +MSK.Split = MSK.String.Split -- Support for old Versions +exports('Split', MSK.String.Split) \ No newline at end of file diff --git a/shared/table.lua b/shared/table.lua new file mode 100644 index 0000000..c80b62c --- /dev/null +++ b/shared/table.lua @@ -0,0 +1,148 @@ +MSK.Table = {} + +MSK.Table.Contains = function(tbl, val) + assert(tbl and type(tbl) == 'table', 'Parameter "tbl" has to be a table on function MSK.Table.Contains') + assert(val, 'Parameter "val" is nil on function MSK.Table.Contains') + + if type(val) == 'table' then + for k, value in pairs(tbl) do + if MSK.Table.Contains(val, value) then + return true + end + end + return false + else + for k, v in pairs(tbl) do + if v == val then + return true + end + end + end + return false +end +MSK.TableContains = MSK.Table.Contains -- Support for old Versions +MSK.Table_Contains = MSK.Table.Contains -- Support for old Versions +exports('TableContains', MSK.Table.Contains) + +MSK.Table.Dump = function(tbl, n) + if not n then n = 0 end + if type(tbl) ~= "table" then return tostring(tbl) end + local s = '{\n' + + for k, v in pairs(tbl) do + if type(k) ~= 'number' then k = '"'..k..'"' end + for i = 1, n, 1 do s = s .. " " end + s = s .. ' ['..k..'] = ' .. MSK.Table.Dump(v, n + 1) .. ',\n' + end + for i = 1, n, 1 do s = s .. " " end + + return s .. '}' +end +MSK.DumpTable = MSK.Table.Dump -- Support for old Versions +exports('TableDump', MSK.Table.Dump) + +MSK.Table.Size = function(tbl) + local count = 0 + + for k, v in pairs(tbl) do + count += 1 + end + + return count +end +exports('TableSize', MSK.Table.Size) + +MSK.Table.Index = function(tbl, val) + for i = 1, #tbl, 1 do + if tbl[i] == val then + return i + end + end + + return -1 +end +exports('TableIndex', MSK.Table.Index) + +MSK.Table.LastIndex = function(tbl, val) + for i = 1, #tbl, -1 do + if tbl[i] == val then + return i + end + end + + return -1 +end +exports('TableLastIndex', MSK.Table.LastIndex) + +MSK.Table.Find = function(tbl, val) + for i = 1, #tbl do + if tbl[i] == val then + return i, val + end + end + + return nil, val +end +exports('TableFind', MSK.Table.Find) + +MSK.Table.Reverse = function(tbl) + local newTbl = {} + + for i = #tbl, 1, -1 do + table.insert(newTbl, tbl[i]) + end + + return newTbl +end +exports('TableReverse', MSK.Table.Reverse) + +MSK.Table.Clone = function(tbl) + assert(tbl and type(tbl) == 'table', 'Parameter "tbl" has to be a table on function MSK.Table.Clone') + + local metatable = getmetatable(t) + local clone = {} + + for k, v in pairs(t) do + if type(v) == 'table' then + target[k] = MSK.Table.Clone(v) + else + target[k] = v + end + end + + setmetatable(clone, metatable) + + return clone +end +exports('TableClone', MSK.Table.Clone) + +-- Credit: https://stackoverflow.com/a/15706820 +MSK.Table.Sort = function(tbl, order) + -- collect the keys + local keys = {} + + for k, _ in pairs(tbl) do + keys[#keys + 1] = k + end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a, b) + return order(tbl, a, b) + end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + + return function() + i = i + 1 + if keys[i] then + return keys[i], tbl[keys[i]] + end + end +end +exports('TableSort', MSK.Table.Sort) \ No newline at end of file