47 Commits

Author SHA1 Message Date
Andy
544ad64779 Update fxmanifest.lua 2025-02-22 23:31:12 +01:00
Andy
43f690e356 Merge pull request #84 from ND-Framework/fix/duplicate-licenses
fix: duplicate character licenses
2025-02-22 23:29:46 +01:00
Andyyy7666
e883c4e64f fix: duplicate character licenses 2025-02-22 23:29:29 +01:00
Andy
5928d89edf Merge pull request #83 from NikartikTheBear/patch-1
fix(fxmanifest typo)
2025-02-16 02:20:21 +01:00
nikartik
9b846dc07e fix(typo) 2025-02-14 22:39:10 +01:00
Andyyy7666
baac4c75dd refactor(server/main): wait for oxmysql 2025-02-05 21:22:26 +01:00
Andyyy7666
fb708cc7e7 Update commands.lua 2025-01-19 18:08:20 +01:00
Andy
1547d310eb Merge pull request #81 from ND-Framework/feat/claim-veh-command
feat(server/comands): claim veh command
2025-01-18 14:41:58 +01:00
Andyyy7666
9d4708f6d9 feat(server/comands): claim veh command 2025-01-18 14:41:41 +01:00
Andy
a7713804f0 Merge pull request #80 from ND-Framework/fix/dv-command-inconsistency
fix(server/commands): dv command inconsistency
2025-01-18 14:40:37 +01:00
Andyyy7666
a9785ce754 fix(server/commands): dv command inconsistency 2025-01-18 14:40:01 +01:00
Andy
fe922e1b98 Merge pull request #79 from ND-Framework/fix/unlock-command-inconsistency
fix(server/commands): unlock command inconsistency
2025-01-18 14:38:42 +01:00
Andyyy7666
b97f42bb0a fix(server/commands): unlock command inconsistency 2025-01-18 14:38:13 +01:00
Andy
d132c12025 Merge pull request #78 from ND-Framework/feat/replace-armor
feat(client): replace armor on revive
2025-01-17 21:13:03 +01:00
Andyyy7666
119b0034bf feat(client): replace armor on revive
When reviving player to heal, replace the armor with the previous amount.
2025-01-17 21:12:43 +01:00
Andyyy7666
622b6fa8b0 tweak: add oxlib as dependency 2025-01-17 20:58:48 +01:00
Andyyy7666
2e6dfa9e5f Update fxmanifest.lua 2025-01-17 20:56:23 +01:00
Andy
4c4166de94 Merge pull request #77 from ND-Framework/feat/lan-identifier
feat(server): lan identifer
2025-01-17 20:53:12 +01:00
Andyyy7666
dea7ac6c8f feat(server): lan identifer
Create fake identifier when using sv_lan
2025-01-17 20:52:28 +01:00
Andy
120d924cae Merge pull request #76 from ND-Framework/tweak/lockpick-tries-convar
tweak(client/vehicle): lockpick tries convar
2025-01-17 20:42:59 +01:00
Andyyy7666
2a263a6c2e tweak(client/vehicle): lockpick tries convar 2025-01-17 20:42:27 +01:00
Andy
4ff4f487a1 Merge pull request #75 from ND-Framework/feat/garage-locations
feat: more default garage locations
2025-01-17 20:36:38 +01:00
Andyyy7666
e26821841b feat: more default garage locations 2025-01-17 20:36:16 +01:00
Andy
e9aafe1f2d Merge pull request #70 from NotSomething0/fix-vehicle-metadata
fix(vehicle): set metadata state for vehicle if non-existent
2024-12-20 21:29:39 +01:00
NotSomething0
6987bb63ae Merge branch 'ND-Framework:main' into fix-vehicle-metadata 2024-05-13 17:17:27 -05:00
NotSomething0
e0c4a8419b fix(vehicle): set metadata state for vehicle if non-existent
- Added debug print for when metadata is storage is skipped
2024-05-11 14:54:57 -05:00
Andyyy7666
66f93bde14 Merge branch 'main' of https://github.com/ND-Framework/ND_Core 2024-03-26 17:08:11 +01:00
Andyyy7666
2460df2f34 feat(server/vehicles): remove vehicles from db 2024-03-26 17:08:09 +01:00
Andy
b79bb6ec7f Merge pull request #68 from Hakkodevelopment/main
small changes
2024-03-25 23:12:04 +01:00
Hakko
eef1bb60f5 bump fxmanifest version 2024-03-25 16:04:43 -06:00
Hakko
1320c4ab7d Update commands.lua 2024-03-25 16:02:24 -06:00
Andyyy7666
2c7aa5723a perf(server/vehicle): getting vehicle types 2024-03-19 01:53:06 +01:00
Andyyy7666
97a8b991ae fix(server/vehicle): taking out impounded vehicle 2024-03-19 01:52:45 +01:00
Andyyy7666
2a3ac3b63b feat(server/player): player group removed event 2024-03-19 01:52:18 +01:00
Andyyy7666
5d3c051149 fix(server/vehicle): calculating time 2024-03-17 14:26:11 +01:00
Andyyy7666
fc82b217e9 fix: clothing not updating 2024-03-16 19:12:34 +01:00
Andyyy7666
284411ce66 fix(server/player): nil group metadata 2024-03-16 16:43:20 +01:00
Andyyy7666
a7257cf68f feat(server/player): group metadata 2024-03-10 00:35:45 +01:00
Andyyy7666
841a5771c5 tweak(server/player): custom group data 2024-03-10 00:01:49 +01:00
Andy
8fd7878ba6 Merge pull request #67 from ND-Framework/tweak/updateCharacter-event
tweak(server/player): also pass which data changed
2024-03-09 19:05:49 +01:00
Andyyy7666
60e86d2038 tweak(server/player): also pass which data changed 2024-03-09 19:05:21 +01:00
Andy
626f0ad06f Merge pull request #66 from ND-Framework/feat/custom-group-info
Feat/custom group info
2024-03-09 19:03:19 +01:00
Andyyy7666
d5c3acbd81 tweak(server/player): adding job group 2024-03-09 19:02:18 +01:00
Andyyy7666
98cba87bec feat(server/player): adding custom group info 2024-03-09 19:00:15 +01:00
Andyyy7666
001fc22ef6 fix: syntax error 2024-02-29 23:17:08 +01:00
Andy
87420e99e9 Merge pull request #65 from ND-Framework/feat/discord-groups
feat: receive groups by discord roles
2024-02-29 22:29:13 +01:00
Andyyy7666
c5597161d9 feat: receive groups by discord roles
Player can receive groups based on the discord roles they have, ace perms are also added when group is received.
2024-02-29 22:28:25 +01:00
10 changed files with 293 additions and 120 deletions

View File

@@ -23,14 +23,17 @@ end)
RegisterNetEvent("ND:revivePlayer", function() RegisterNetEvent("ND:revivePlayer", function()
if source == "" then return end if source == "" then return end
local veh = GetVehiclePedIsIn(cache.ped) local oldPed = cache.ped
local veh = GetVehiclePedIsIn(oldPed)
local seat = cache.seat local seat = cache.seat
local coords = GetEntityCoords(cache.ped) local coords = GetEntityCoords(oldPed)
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(cache.ped), true, true, false) local armor = GetPedArmour(oldPed)
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(oldPed), true, true, false)
local ped = PlayerPedId() local ped = PlayerPedId()
if cache.ped ~= ped then if oldPed ~= ped then
DeleteEntity(cache.ped) DeleteEntity(oldPed)
ClearAreaOfPeds(coords.x, coords.y, coords.z, 0.2, false) ClearAreaOfPeds(coords.x, coords.y, coords.z, 0.2, false)
end end
@@ -43,6 +46,7 @@ RegisterNetEvent("ND:revivePlayer", function()
SetBlockingOfNonTemporaryEvents(ped, false) SetBlockingOfNonTemporaryEvents(ped, false)
SetPedCanRagdollFromPlayerImpact(ped, true) SetPedCanRagdollFromPlayerImpact(ped, true)
ClearPedTasksImmediately(ped) ClearPedTasksImmediately(ped)
SetPedArmour(ped, armor)
if veh and veh ~= 0 then if veh and veh ~= 0 then
SetPedIntoVehicle(ped, veh, seat) SetPedIntoVehicle(ped, veh, seat)

View File

@@ -15,7 +15,8 @@ Config = {
requireKeys = GetConvarInt("core:requireKeys", 1) == 1, requireKeys = GetConvarInt("core:requireKeys", 1) == 1,
useInventoryForKeys = GetConvarInt("core:useInventoryForKeys", 1) == 1, useInventoryForKeys = GetConvarInt("core:useInventoryForKeys", 1) == 1,
groups = json.decode(GetConvar("core:groups", "[]")), groups = json.decode(GetConvar("core:groups", "[]")),
compatibility = json.decode(GetConvar("core:compatibility", "[]")) compatibility = json.decode(GetConvar("core:compatibility", "[]")),
lockpickTries = GetConvarInt("core:lockpickTries", 3)
} }
-- Discord rich presence. -- Discord rich presence.

View File

@@ -1,4 +1,14 @@
return { return {
{
garageType = "land",
groups = {"lsfd"},
ped = vector4(370.9027, -593.8090, 28.8681, 73.6009),
vehicleSpawns = {
vec4(366.7840, -591.4883, 28.7261, 339.6823),
vec4(365.0753, -582.8641, 28.7156, 135.0064),
vec4(357.4239, -604.7719, 28.6767, 177.1355),
}
},
{ {
garageType = "land", garageType = "land",
groups = {"sahp", "lspd", "bcso"}, groups = {"sahp", "lspd", "bcso"},
@@ -240,4 +250,52 @@ return {
vector4(216.56, -801.90, 30.79, 69.39) vector4(216.56, -801.90, 30.79, 69.39)
} }
}, },
{
garageType = "land",
ped = vector4(587.5941, 2744.2844, 42.0691, 181.0514),
vehicleSpawns = {
vector4(584.3921, 2721.3599, 41.6483, 184.3260),
vector4(577.1069, 2736.2322, 41.6097, 184.6912),
vector4(577.9459, 2721.0010, 41.6481, 185.1414),
vector4(574.1685, 2735.7288, 41.6397, 184.5562)
}
},
{
garageType = "land",
ped = vector4(2746.1726, 3458.7378, 55.8272, 245.1009),
vehicleSpawns = {
vector4(2768.2136, 3456.2710, 55.2840, 67.7897),
vector4(2759.3218, 3451.1448, 55.4786, 248.0150),
vector4(2763.6526, 3445.0544, 55.4741, 66.9754),
vector4(2787.2947, 3467.1001, 54.9407, 247.4356),
vector4(2773.9514, 3471.6238, 55.0407, 246.8264)
}
},
{
garageType = "land",
ped = vector4(120.4042, 6623.5190, 31.9593, 228.8283),
vehicleSpawns = {
vector4(155.9047, 6593.3252, 31.4343, 359.3789),
vector4(155.7900, 6602.6978, 31.4463, 358.8232),
vector4(145.8267, 6614.0996, 31.4007, 178.7948),
vector4(145.6977, 6602.8950, 31.4397, 181.0616),
vector4(132.4042, 6585.2139, 31.5501, 91.0906)
}
},
{
garageType = "heli",
groups = {"lspd"},
ped = vector4(465.6194, -985.4730, 43.6918, 0.8591),
vehicleSpawns = {
vector4(449.3105, -981.1057, 44.0788, 359.6042)
}
},
{
garageType = "heli",
groups = {"lsfd"},
ped = vector4(339.6271, -581.0325, 74.1656, 267.8232),
vehicleSpawns = {
vector4(351.3463, -588.1304, 74.1698, 108.5617)
}
}
} }

View File

@@ -356,8 +356,9 @@ AddStateBagChangeHandler("locked", nil, function(bagName, key, value, reserved,
end) end)
end) end)
lib.callback.register("ND_Vehicles:getProps", function(netId) local function getProps(veh)
local veh = getVehFromNetId(netId) if not veh or not DoesEntityExist(veh) then return end
local props = lib.getVehicleProperties(veh) local props = lib.getVehicleProperties(veh)
local colorPrimary, colorSecondary = GetVehicleColours(veh) local colorPrimary, colorSecondary = GetVehicleColours(veh)
if not props then return end if not props then return end
@@ -368,7 +369,18 @@ lib.callback.register("ND_Vehicles:getProps", function(netId)
props.className = vehicleClassNames[GetVehicleClass(veh)] props.className = vehicleClassNames[GetVehicleClass(veh)]
props.makeName = GetLabelText(GetMakeNameFromVehicleModel(props.model)) props.makeName = GetLabelText(GetMakeNameFromVehicleModel(props.model))
props.modelName = GetLabelText(GetDisplayNameFromVehicleModel(props.model)) props.modelName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
return props return props
end
lib.callback.register("ND_Vehicles:getProps", function(netId)
local veh = getVehFromNetId(netId)
return getProps(veh)
end)
lib.callback.register("ND_Vehicles:getPropsFromCurrentVeh", function()
local veh = GetVehiclePedIsIn(cache.ped)
return getProps(veh)
end) end)
lib.callback.register("ND_Vehicles:getVehicleModelMakeLabel", function(model) lib.callback.register("ND_Vehicles:getVehicleModelMakeLabel", function(model)
@@ -597,7 +609,7 @@ local function lockpickVehicle()
} }
lib.requestAnimDict("veh@break_in@0h@p_m_one@") lib.requestAnimDict("veh@break_in@0h@p_m_one@")
for i=1, 7 do for i=1, Config.lockpickTries do
TaskPlayAnimAdvanced(cache.ped, "veh@break_in@0h@p_m_one@", "std_force_entry_ds", pos.x, pos.y, pos.z+0.025, rot.x, rot.y, rot.z, 8.0, 8.0, 1800, 28, 0.1) TaskPlayAnimAdvanced(cache.ped, "veh@break_in@0h@p_m_one@", "std_force_entry_ds", pos.x, pos.y, pos.z+0.025, rot.x, rot.y, rot.z, 8.0, 8.0, 1800, 28, 0.1)
local dificulty = dificulties[math.random(1, #dificulties)] local dificulty = dificulties[math.random(1, #dificulties)]
local success = lib.skillCheck(dificulty) local success = lib.skillCheck(dificulty)

View File

@@ -2,7 +2,7 @@
author "Andyyy#7666" author "Andyyy#7666"
description "ND Framework Core" description "ND Framework Core"
version "2.1.2" version "2.3.2"
fx_version "cerulean" fx_version "cerulean"
game "gta5" game "gta5"
@@ -37,7 +37,10 @@ files {
"compatibility/**/locale.lua" "compatibility/**/locale.lua"
} }
dependency "oxmysql" dependencies {
"ox_lib",
"oxmysql"
}
-- below were used with backwards compatibility but could interfere with resources checking if the resources are started. -- below were used with backwards compatibility but could interfere with resources checking if the resources are started.
-- provide "es_extended" -- provide "es_extended"

View File

@@ -15,7 +15,7 @@ local moneyActions = {
} }
lib.addCommand("setmoney", { lib.addCommand("setmoney", {
help = "Admin command, manage player money.", help = "Admin command, set a players money.",
restricted = "group.admin", restricted = "group.admin",
params = { params = {
{ {
@@ -54,7 +54,7 @@ lib.addCommand("setmoney", {
duration = 10000 duration = 10000
}) })
if not source then return end if not source or source == 0 then return end
TriggerClientEvent("chat:addMessage", source, { TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235}, color = {50, 100, 235},
multiline = true, multiline = true,
@@ -96,7 +96,7 @@ lib.addCommand("setjob", {
duration = 10000 duration = 10000
}) })
if not source then return end if not source or source == 0 then return end
TriggerClientEvent("chat:addMessage", source, { TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235}, color = {50, 100, 235},
multiline = true, multiline = true,
@@ -155,7 +155,7 @@ lib.addCommand("setgroup", {
return return
end end
if not source then return end if not source or source == 0 then return end
TriggerClientEvent("chat:addMessage", source, { TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235}, color = {50, 100, 235},
multiline = true, multiline = true,
@@ -164,7 +164,7 @@ lib.addCommand("setgroup", {
end) end)
lib.addCommand("skin", { lib.addCommand("skin", {
help = "Admin command, set player into character clothing menu.", help = "Admin command, show character clothing menu for player.",
restricted = "group.admin", restricted = "group.admin",
params = { params = {
{ {
@@ -178,7 +178,7 @@ lib.addCommand("skin", {
end) end)
lib.addCommand("character", { lib.addCommand("character", {
help = "Admin command, set player into character selection menu.", help = "Admin command, show character selection menu for player.",
restricted = "group.admin", restricted = "group.admin",
params = { params = {
{ {
@@ -206,7 +206,7 @@ lib.addCommand("pay", {
} }
} }
}, function(source, args, raw) }, function(source, args, raw)
if not source then return end if not source or source == 0 then return end
local player = NDCore.getPlayer(source) local player = NDCore.getPlayer(source)
local targetPlayer = NDCore.getPlayer(args.target) local targetPlayer = NDCore.getPlayer(args.target)
@@ -262,38 +262,22 @@ lib.addCommand("pay", {
end) end)
lib.addCommand("unlock", { lib.addCommand("unlock", {
help = "Admin Command, force unlock vehicle.", help = "Admin Command, force unlock a vehicle.",
restricted = "group.admin", restricted = "group.admin",
}, function(source, args, raw) }, function(source, args, raw)
local ped = GetPlayerPed(source) local ped = GetPlayerPed(source)
local playerVeh = GetVehiclePedIsIn(ped)
local coords = GetEntityCoords(ped) local coords = GetEntityCoords(ped)
local vehicles = GetAllVehicles() local veh = lib.getClosestVehicle(coords, 2.5, true)
local maxDistance = 2.0
local closestVehicle
if not playerVeh or playerVeh == 0 or not DoesEntityExist(playerVeh) then if not veh then return end
for i=1, #vehicles do
local vehicle = vehicles[i]
local vehicleCoords = GetEntityCoords(vehicle)
local distance = #(coords-vehicleCoords)
if distance < maxDistance then local state = Entity(veh).state
maxDistance = distance
closestVehicle = vehicle
end
end
if not closestVehicle or not DoesEntityExist(closestVehicle) then return end
local state = Entity(closestVehicle).state
state.locked = false
else
local state = Entity(playerVeh).state
state.hotwired = true state.hotwired = true
end state.locked = false
end) end)
lib.addCommand("revive", { lib.addCommand("revive", {
help = "Admin command, revive player.", help = "Admin command, revive a player.",
restricted = "group.admin", restricted = "group.admin",
params = { params = {
{ {
@@ -321,48 +305,36 @@ lib.addCommand("dv", {
} }
}, function(source, args, raw) }, function(source, args, raw)
local ped = GetPlayerPed(source) local ped = GetPlayerPed(source)
local veh = GetVehiclePedIsIn(ped)
if veh and veh ~= 0 and DoesEntityExist(veh) then
DeleteEntity(veh)
return TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235},
multiline = true,
args = {"Staff action", "deleted 1 vehicle"}
})
end
local count = 0
local coords = GetEntityCoords(ped) local coords = GetEntityCoords(ped)
local count = 0
local message = nil
local veh = lib.getClosestVehicle(coords, 3.0)
if args.range then if args.range then
for _, veh in ipairs(GetAllVehicles()) do local vehicles = lib.getNearbyVehicles(coords, args.range)
local vehDist = #(GetEntityCoords(veh) - coords) count = #vehicles
if vehDist < args.range then
for i=1, count do
local veh = vehicles[i]
DeleteEntity(veh.vehicle)
end
elseif veh then
DeleteEntity(veh) DeleteEntity(veh)
count += 1 count = 1
end
end
return TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235},
multiline = true,
args = {"Staff action", ("deleted %d vehicles"):format(count)}
})
end end
local closest, dist if count == 0 then
for _, veh in ipairs(GetAllVehicles()) do message = {"Staff action [dv]", "no vehicles found"}
local vehDist = #(GetEntityCoords(veh) - coords) elseif count == 1 then
if vehDist < 5.0 and not closest or (dist and dist > vehDist) then message = {"Staff action [dv]", "deleted 1 vehicle"}
closest = veh else
dist = vehDist message = {"Staff action [dv]", ("deleted %d vehicles"):format(count)}
end
end end
if not closest then return "no vehicle found nearby" end
DeleteEntity(closest)
TriggerClientEvent("chat:addMessage", source, { TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235}, color = {50, 100, 235},
multiline = true, multiline = true,
args = {"Staff action", "deleted 1 vehicle"} args = message
}) })
end) end)
@@ -433,7 +405,7 @@ lib.addCommand("unfreeze", {
end) end)
lib.addCommand("vehicle", { lib.addCommand("vehicle", {
help = "Admin command, unfreeze a player.", help = "Admin command, spawn a vehicle.",
restricted = "group.admin", restricted = "group.admin",
params = { params = {
{ {
@@ -466,3 +438,45 @@ lib.addCommand("vehicle", {
Wait(100) Wait(100)
end end
end) end)
lib.addCommand("claim-veh", {
help = "Admin command, add a copy of the vehicle you're inside to players garage.",
restricted = "group.admin",
params = {
{
name = "target",
type = "playerId",
help = "Target player's server id"
}
}
}, function(source, args, raw)
local player = NDCore.getPlayer(source)
if not player then return end
local targetPlayer = NDCore.getPlayer(args.target)
if not targetPlayer then
return player.notify({
title = "Player not found!",
description = "Target player not found, make sure they select a charcter!",
type = "error"
})
end
local properties = lib.callback.await("ND_Vehicles:getPropsFromCurrentVeh", source)
if not properties then
return player.notify({
title = "Vehicle data not found!",
description = "The vehicle properties data was not found!",
type = "error"
})
end
NDCore.setVehicleOwned(targetPlayer.id, properties, true)
player.notify({
title = "Vehicle added!",
description = ("The vehicle has now been added to %s's garage!"):format(targetPlayer.name),
type = "success"
})
end)

View File

@@ -1,3 +1,10 @@
function NDCore.getPlayerIdentifierByType(src, indentifierType)
if Config.sv_lan then
return ("%s:sv_lan"):format(indentifierType)
end
return GetPlayerIdentifierByType(src, indentifierType)
end
---@param src number ---@param src number
---@return table ---@return table
function NDCore.getPlayer(src) function NDCore.getPlayer(src)

View File

@@ -24,8 +24,10 @@ Config = {
groups = json.decode(GetConvar("core:groups", "[]")), groups = json.decode(GetConvar("core:groups", "[]")),
admins = json.decode(GetConvar("core:admins", "[]")), admins = json.decode(GetConvar("core:admins", "[]")),
adminDiscordRoles = json.decode(GetConvar("core:adminDiscordRoles", "[]")), adminDiscordRoles = json.decode(GetConvar("core:adminDiscordRoles", "[]")),
groupRoles = json.decode(GetConvar("core:groupRoles", "[]")),
multiCharacter = false, multiCharacter = false,
compatibility = json.decode(GetConvar("core:compatibility", "[]")) compatibility = json.decode(GetConvar("core:compatibility", "[]")),
sv_lan = GetConvar("sv_lan", "false") == "true",
} }
SetConvarServerInfo("Discord", Config.discordInvite) SetConvarServerInfo("Discord", Config.discordInvite)
@@ -42,6 +44,11 @@ local function getIdentifierList(src)
list[identifierType] = identifier list[identifierType] = identifier
end end
end end
if Config.sv_lan then
list[Config.characterIdentifier] = NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)
end
return list return list
end end
@@ -51,6 +58,10 @@ AddEventHandler("playerJoining", function(oldId)
PlayersInfo[src] = tempPlayersInfo[oldTempId] PlayersInfo[src] = tempPlayersInfo[oldTempId]
tempPlayersInfo[oldTempId] = nil tempPlayersInfo[oldTempId] = nil
if Config.sv_lan then
lib.addPrincipal(("player.%s"):format(src), "group.admin")
end
if Config.multiCharacter then return end if Config.multiCharacter then return end
Wait(3000) Wait(3000)
@@ -102,7 +113,7 @@ AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
if mainIdentifier and Config.discordBotToken ~= "false" and Config.discordGuildId ~= "false" then if mainIdentifier and Config.discordBotToken ~= "false" and Config.discordGuildId ~= "false" then
discordInfo = checkDiscordIdentifier(identifiers) discordInfo = checkDiscordIdentifier(identifiers)
if not discordInfo and Config.discordMemeberRequired then if not discordInfo and Config.discordMemeberRequired and not Config.sv_lan then
deferrals.done(("Your discord was not found, join our discord here: %s."):format(Config.discordInvite)) deferrals.done(("Your discord was not found, join our discord here: %s."):format(Config.discordInvite))
Wait(0) Wait(0)
end end
@@ -111,6 +122,17 @@ AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
deferrals.update("Connecting...") deferrals.update("Connecting...")
Wait(0) Wait(0)
if Config.sv_lan then
tempPlayersInfo[tempSrc] = {
identifiers = {
[Config.characterIdentifier] = "sv_lan"
},
discord = discordInfo
}
deferrals.done()
return
end
if mainIdentifier then if mainIdentifier then
tempPlayersInfo[tempSrc] = { tempPlayersInfo[tempSrc] = {
identifiers = identifiers, identifiers = identifiers,
@@ -138,7 +160,7 @@ AddEventHandler("onResourceStop", function(name)
end end
end) end)
SetTimeout(500, function() MySQL.ready(function()
NDCore.loadSQL({ NDCore.loadSQL({
"database/characters.sql", "database/characters.sql",
"database/vehicles.sql" "database/vehicles.sql"
@@ -155,7 +177,7 @@ RegisterNetEvent("ND:playerEliminated", function(info)
}) })
end) end)
RegisterNetEvent("ND::updateClothing", function(clothing) RegisterNetEvent("ND:updateClothing", function(clothing)
local src = source local src = source
local player = NDCore.getPlayer(src) local player = NDCore.getPlayer(src)
if not player or not clothing or type(clothing) ~= "table" then return end if not player or not clothing or type(clothing) ~= "table" then return end

View File

@@ -113,8 +113,8 @@ local function createCharacterTable(info)
TriggerEvent("ND:moneyChange", self.source, key, value, "set", reason) TriggerEvent("ND:moneyChange", self.source, key, value, "set", reason)
end end
end end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self)) self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), key)
TriggerEvent("ND:updateCharacter", self) TriggerEvent("ND:updateCharacter", self, key)
end end
---@param key string|table ---@param key string|table
@@ -128,8 +128,8 @@ local function createCharacterTable(info)
else else
self.metadata[key] = value self.metadata[key] = value
end end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self)) self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "metadata")
TriggerEvent("ND:updateCharacter", self) TriggerEvent("ND:updateCharacter", self, "metadata")
return self.metadata return self.metadata
end end
@@ -221,12 +221,24 @@ local function createCharacterTable(info)
} }
if licenses then if licenses then
local found = false
for i=1, #licenses do
if licenses[i].type == licenseType then
self.metadata.licenses[i] = license
found = true
break
end
end
if not found then
self.metadata.licenses[#licenses+1] = license self.metadata.licenses[#licenses+1] = license
end
else else
self.metadata.licenses = {license} self.metadata.licenses = {license}
end end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self)) self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "metadata")
TriggerEvent("ND:updateCharacter", self) TriggerEvent("ND:updateCharacter", self, "metadata")
end end
function self.getLicense(identifier) function self.getLicense(identifier)
@@ -309,6 +321,12 @@ local function createCharacterTable(info)
self.addGroup("admin") self.addGroup("admin")
end end
end end
for group, role in pairs(Config.groupRoles) do
if lib.table.contains(roles, role) then
self.addGroup(group)
end
end
end end
for name, _ in pairs(self.groups) do for name, _ in pairs(self.groups) do
@@ -323,12 +341,15 @@ local function createCharacterTable(info)
---@param rank number ---@param rank number
---@param isJob boolean ---@param isJob boolean
---@return boolean ---@return boolean
function self.addGroup(name, rank, isJob) function self.addGroup(name, rank, customGroup, isJob)
local groupRank = tonumber(rank) or 1 local groupRank = tonumber(rank) or 1
local groupInfo = Config.groups?[name] local groupInfo = lib.table.deepclone(Config.groups?[name] or {})
local bossRank = groupInfo and groupInfo.minimumBossRank local bossRank = groupInfo?.minimumBossRank
for k, v in pairs(customGroup or {}) do
groupInfo[k] = v
end
-- if not groupInfo then return end
if isJob then if isJob then
for _, group in pairs(self.groups) do for _, group in pairs(self.groups) do
group.isJob = nil group.isJob = nil
@@ -337,16 +358,17 @@ local function createCharacterTable(info)
self.groups[name] = { self.groups[name] = {
name = name, name = name,
label = groupInfo and groupInfo.label or name, label = groupInfo?.label or name,
rankName = groupInfo and groupInfo.ranks[groupRank] or groupRank, rankName = groupInfo?.ranks?[groupRank] or groupRank,
rank = groupRank, rank = groupRank,
isJob = isJob, isJob = isJob,
isBoss = bossRank and groupRank >= bossRank isBoss = bossRank and groupRank >= bossRank,
metadata = groupInfo.metadata or {}
} }
if not isJob then if not isJob then
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self)) self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "groups")
TriggerEvent("ND:updateCharacter", self) TriggerEvent("ND:updateCharacter", self, "groups")
end end
lib.addPrincipal(self.source, ("group.%s"):format(name)) lib.addPrincipal(self.source, ("group.%s"):format(name))
@@ -371,8 +393,9 @@ local function createCharacterTable(info)
end end
self.groups[name] = nil self.groups[name] = nil
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self)) self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "groups")
TriggerEvent("ND:updateCharacter", self) TriggerEvent("ND:updateCharacter", self, "groups")
TriggerEvent("ND:groupRemoved", self, group)
lib.removePrincipal(self.source, ("group.%s"):format(name)) lib.removePrincipal(self.source, ("group.%s"):format(name))
return group return group
end end
@@ -382,13 +405,13 @@ local function createCharacterTable(info)
---@return boolean ---@return boolean
function self.setJob(name, rank) function self.setJob(name, rank)
self.removeGroup(self.job) self.removeGroup(self.job)
local job = self.addGroup(name, rank, true) local job = self.addGroup(name, rank, nil, true)
if job then if job then
self.job = job.name self.job = job.name
self.jobInfo = job self.jobInfo = job
end end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self)) self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "job")
TriggerEvent("ND:updateCharacter", self) TriggerEvent("ND:updateCharacter", self, "job")
return job return job
end end
@@ -415,7 +438,7 @@ end
---@param info table ---@param info table
---@return table ---@return table
function NDCore.newCharacter(src, info) function NDCore.newCharacter(src, info)
local identifier = GetPlayerIdentifierByType(src, Config.characterIdentifier) local identifier = NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)
if not identifier then return end if not identifier then return end
local charInfo = { local charInfo = {
@@ -457,7 +480,7 @@ end
function NDCore.fetchCharacter(id, src) function NDCore.fetchCharacter(id, src)
local result local result
if src then if src then
result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ? and identifier = ?", {id, GetPlayerIdentifierByType(src, Config.characterIdentifier)}) result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ? and identifier = ?", {id, NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)})
else else
result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ?", {id}) result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ?", {id})
end end
@@ -486,7 +509,7 @@ end
---@return table ---@return table
function NDCore.fetchAllCharacters(src) function NDCore.fetchAllCharacters(src)
local characters = {} local characters = {}
local result = MySQL.query.await("SELECT * FROM nd_characters WHERE identifier = ?", {GetPlayerIdentifierByType(src, Config.characterIdentifier)}) local result = MySQL.query.await("SELECT * FROM nd_characters WHERE identifier = ?", {NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)})
for i=1, #result do for i=1, #result do
local info = result[i] local info = result[i]

View File

@@ -1,6 +1,7 @@
local ox_inventory local ox_inventory
local inventoryStarted = false local inventoryStarted = false
local spawnedPlayerVehicles = {} local spawnedPlayerVehicles = {}
local vehicleTypes = json.decode(GetResourceKvpString("ND_Core:vehTypes") or "[]")
NDCore.isResourceStarted("ox_inventory", function(started) NDCore.isResourceStarted("ox_inventory", function(started)
inventoryStarted = started inventoryStarted = started
@@ -8,16 +9,24 @@ NDCore.isResourceStarted("ox_inventory", function(started)
ox_inventory = exports.ox_inventory ox_inventory = exports.ox_inventory
end) end)
local function getVehicleType(model) local function getVehicleType(coords, model)
local tempVehicle = CreateVehicle(model, 0, 0, 0, 0, true, true) if vehicleTypes[model] then
return vehicleTypes[model]
end
local tempVehicle = CreateVehicle(model, coords.x, coords.y, coords.z-5.0, coords.w, true, false)
local time = os.time() local time = os.time()
while not DoesEntityExist(tempVehicle) and time-os.time() < 5 do Wait(5) end
while not DoesEntityExist(tempVehicle) and os.time()-time < 5 do Wait(0) end
if not DoesEntityExist(tempVehicle) then return end if not DoesEntityExist(tempVehicle) then return end
local entityType = GetVehicleType(tempVehicle)
local vehType = GetVehicleType(tempVehicle)
DeleteEntity(tempVehicle) DeleteEntity(tempVehicle)
return entityType
vehicleTypes[model] = vehType
SetResourceKvp("ND_Core:vehTypes", json.encode(vehicleTypes))
return vehType
end end
local function generatePlate() local function generatePlate()
@@ -99,6 +108,15 @@ function NDCore.getVehicle(entity)
DeleteEntity(entity) DeleteEntity(entity)
end end
-- remvoe vehicle from db.
function self.remove(keepEntity)
if not keepEntity and DoesEntityExist(entity) then
DeleteEntity(entity)
end
MySQL.query("DELETE FROM nd_vehicles WHERE id = ?", {self.id})
end
--- set vehicle properties --- set vehicle properties
---@param props table ---@param props table
function self.setProperties(props) function self.setProperties(props)
@@ -156,13 +174,22 @@ function NDCore.getVehicle(entity)
function self.setMetadata(key, value) function self.setMetadata(key, value)
self.metadata[key] = value self.metadata[key] = value
if DoesEntityExist(entity) then if DoesEntityExist(entity) then
local state = Entity(self.entity).state local state = Entity(self.entity).state
local metadata = state.metadata
metadata[key] = value if not state.metadata then
state.metadata = metadata state.metadata = self.metadata
else
state.metadata[key] = value
end end
if not self.id or not self.owner then return end end
if not self.id or not self.owner then
lib.print.debug(('Skipped storing metadata for vehicle %s as it does not have an id/owner associated with it.'):format(self.entity))
return
end
MySQL.query("UPDATE nd_vehicles SET metadata = ? WHERE id = ?", {json.encode(self.metadata), self.id}) MySQL.query("UPDATE nd_vehicles SET metadata = ? WHERE id = ?", {json.encode(self.metadata), self.id})
end end
@@ -253,14 +280,14 @@ function NDCore.createVehicle(info)
end end
local model = info.model or properties.model local model = info.model or properties.model
local vehType = getVehicleType(model) local vehType = getVehicleType(spawnCoords, model)
if not vehType then if not vehType then
return Citizen.Trace("NDCore.createVehicle", "vehType not found") return Citizen.Trace("NDCore.createVehicle", "vehType not found")
end end
local veh = CreateVehicleServerSetter(model, vehType, spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w) local veh = CreateVehicleServerSetter(model, vehType, spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w)
local time = os.time() local time = os.time()
while not DoesEntityExist(veh) and time-os.time() < 5 do Wait(5) end while not DoesEntityExist(veh) and os.time()-time < 5 do Wait(5) end
if not veh or not DoesEntityExist(veh) then if not veh or not DoesEntityExist(veh) then
return Citizen.Trace("NDCore.createVehicle", "vehicle entity doesn't exist") return Citizen.Trace("NDCore.createVehicle", "vehicle entity doesn't exist")
end end
@@ -411,7 +438,8 @@ function NDCore.spawnOwnedVehicle(source, vehicleId, coords, heading)
if not player then return end if not player then return end
local vehicle = NDCore.getVehicleById(vehicleId) local vehicle = NDCore.getVehicleById(vehicleId)
if not vehicle or not vehicle.available or vehicle.owner ~= player.id then return end if not vehicle or vehicle.owner ~= player.id then return end
if not vehicle.available and not vehicle.impounded then return end
MySQL.query.await("UPDATE nd_vehicles SET stored = ? WHERE id = ?", {0, vehicleId}) MySQL.query.await("UPDATE nd_vehicles SET stored = ? WHERE id = ?", {0, vehicleId})
@@ -701,6 +729,11 @@ RegisterNetEvent("ND_Vehicles:takeVehicle", function(vehId, locations)
local vehicle = NDCore.getVehicleById(vehId) local vehicle = NDCore.getVehicleById(vehId)
local player = NDCore.getPlayer(src) local player = NDCore.getPlayer(src)
if not player or not vehicle or vehicle.owner ~= player.id then return end if not player or not vehicle or vehicle.owner ~= player.id then return end
local info = NDCore.spawnOwnedVehicle(src, vehicle.id, isParkingAvailable(locations))
if not info then return end
TriggerClientEvent("ND_Vehicles:blip", src, info.netId, true)
if vehicle.impounded then if vehicle.impounded then
local reclaimPrice = vehicle.metadata.impoundReclaimPrice or 200 local reclaimPrice = vehicle.metadata.impoundReclaimPrice or 200
if not player.deductMoney("bank", reclaimPrice, "Vehicle impound reclaim") then if not player.deductMoney("bank", reclaimPrice, "Vehicle impound reclaim") then
@@ -719,10 +752,6 @@ RegisterNetEvent("ND_Vehicles:takeVehicle", function(vehId, locations)
}) })
MySQL.query.await("UPDATE nd_vehicles SET impounded = ? WHERE id = ?", {0, vehicle.id}) MySQL.query.await("UPDATE nd_vehicles SET impounded = ? WHERE id = ?", {0, vehicle.id})
end end
local info = NDCore.spawnOwnedVehicle(src, vehicle.id, isParkingAvailable(locations))
if not info then return end
TriggerClientEvent("ND_Vehicles:blip", src, info.netId, true)
end) end)
lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src) lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src)