54 Commits

Author SHA1 Message Date
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
Andyyy7666
898b9aefe9 feat(server/player): updatecharacter server event 2024-02-28 14:12:18 +01:00
Andyyy7666
5545650dd5 feat: impound non parked vehicles 2024-02-27 23:13:40 +01:00
Andy
f4f01a5b1c fix: config discord invinte 2024-02-27 20:43:15 +01:00
Andyyy7666
3252118f93 tweak: move clothing menu command to core 2024-02-25 23:54:10 +01:00
Andyyy7666
9d4708a1f8 tweak(server/player): save inventory when character created 2024-02-25 23:43:00 +01:00
Andyyy7666
d0d04ae282 tweak(death): damage event for ambulance 2024-02-17 23:57:42 +01:00
Andyyy7666
c005c1b28b tweak(client/death): player death checks 2024-02-12 23:28:18 +01:00
Andyyy7666
590044b5d6 refactor(client): revive function 2024-02-12 23:27:43 +01:00
Andyyy7666
3146172c0c fix: register unloaded event 2024-02-04 16:44:55 +01:00
Andy
2ce47ef8d1 Merge pull request #62 from ND-Framework/tweak/peds-clothing-command
tweak(client/peds): copying clothing
2024-01-30 14:38:25 +01:00
Andyyy7666
6258651d8b tweak(client/peds): copying clothing 2024-01-30 14:37:44 +01:00
Andy
eecbc8f690 Merge pull request #59 from Hakkodevelopment/patch-1
Fix: Command grammar/spelling mistakes/fluidity
2024-01-26 04:29:52 +01:00
Andyyy7666
1d25b54e0f tweak: notifiacitons 2024-01-26 04:16:24 +01:00
Hakko
e18389a52a Fix: Command grammar/spelling mistakes/fluidity 2024-01-21 21:06:51 -07:00
13 changed files with 367 additions and 171 deletions

View File

@@ -29,15 +29,14 @@ AddEventHandler("gameEventTriggered", function(name, args)
local victim = args[1]
if not IsPedAPlayer(victim) or NetworkGetPlayerIndexFromPed(victim) ~= cache.playerId then return end
if not IsPedDeadOrDying(victim, true) then
local hit, bone = GetPedLastDamageBone(victim)
if hit and usingAmbulance then
local damageWeapon = ambulance:getLastDamagingWeapon(victim)
return damageWeapon and ambulance:updateBodyDamage(bone, damageWeapon)
end
return
ambulance:updateBodyDamage(bone, damageWeapon)
end
if not IsPedDeadOrDying(victim, true) or GetEntityHealth(victim) > 100 then return end
local killerEntity, deathCause = GetPedSourceOfDeath(cache.ped), GetPedCauseOfDeath(cache.ped)
local killerClientId = NetworkGetPlayerIndexFromPed(killerEntity)
if killerEntity ~= cache.ped and killerClientId and NetworkIsPlayerActive(killerClientId) then

View File

@@ -22,5 +22,54 @@ RegisterNetEvent("ND:updateLastLocation", function(location)
end)
RegisterNetEvent("ND:revivePlayer", function()
NDCore.revivePlayer(true)
if source == "" then return end
local oldPed = cache.ped
local veh = GetVehiclePedIsIn(oldPed)
local seat = cache.seat
local coords = GetEntityCoords(oldPed)
local armor = GetPedArmour(oldPed)
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(oldPed), true, true, false)
local ped = PlayerPedId()
if oldPed ~= ped then
DeleteEntity(oldPed)
ClearAreaOfPeds(coords.x, coords.y, coords.z, 0.2, false)
end
SetEntityInvincible(ped, false)
FreezeEntityPosition(ped, false)
SetEntityVisible(ped, true)
SetEveryoneIgnorePlayer(ped, false)
SetPedCanBeTargetted(ped, true)
SetEntityCanBeDamaged(ped, true)
SetBlockingOfNonTemporaryEvents(ped, false)
SetPedCanRagdollFromPlayerImpact(ped, true)
ClearPedTasksImmediately(ped)
SetPedArmour(ped, armor)
if veh and veh ~= 0 then
SetPedIntoVehicle(ped, veh, seat)
end
end)
RegisterNetEvent("ND:characterUnloaded")
RegisterNetEvent("ND:clothingMenu", function()
if GetResourceState("fivem-appearance") ~= "started" then return end
local function customize(appearance)
if not appearance then return end
TriggerServerEvent("ND:updateClothing", appearance)
end
exports["fivem-appearance"]:startPlayerCustomization(customize, {
ped = false,
headBlend = true,
faceFeatures = true,
headOverlays = true,
components = true,
props = true,
tattoos = true
})
end)

View File

@@ -33,57 +33,9 @@ function NDCore.getConfig(info)
return Config[info]
end
function NDCore.revivePlayer(reset, keepDead)
local usingAmbulance = GetResourceState("ND_Ambulance") == "started"
if not keepDead then
LocalPlayer.state.dead = false
if usingAmbulance then
local state = Player(cache.serverId).state
state:set("isDead", false, true)
end
end
local veh = GetVehiclePedIsIn(cache.ped)
local seat = cache.seat
local coords = GetEntityCoords(cache.ped)
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(cache.ped), true, true, false)
local ped = PlayerPedId()
if cache.ped ~= ped then
DeleteEntity(cache.ped)
ClearAreaOfPeds(coords.x, coords.y, coords.z, 0.2, false)
end
SetEntityInvincible(ped, false)
FreezeEntityPosition(ped, false)
SetEntityVisible(ped, true)
SetEveryoneIgnorePlayer(ped, false)
SetPedCanBeTargetted(ped, true)
SetEntityCanBeDamaged(ped, true)
SetBlockingOfNonTemporaryEvents(ped, false)
SetPedCanRagdollFromPlayerImpact(ped, true)
ClearPedTasksImmediately(ped)
if veh and veh ~= 0 then
SetPedIntoVehicle(ped, veh, seat)
end
if reset and GetPedMovementClipset(ped) == `move_m@injured` then
ClearEntityLastDamageEntity(ped)
SetPedMoveRateOverride(ped, 1.0)
ResetPedMovementClipset(ped, 0)
end
if reset and usingAmbulance then
exports["ND_Ambulance"]:resetBodyDamage()
end
end
function NDCore.notify(...)
if GetResourceState("ModernHUD") == "started" then
exports["ModernHUD"]:notify(...)
elseif GetResourceState("ox_lib") == "started" then
lib.notify(...)
end
end
for name, func in pairs(NDCore) do
if type(func) == "function" then

View File

@@ -7,7 +7,7 @@ Config = {
discordAsset = GetConvar("core:discordAsset", "andyyy"),
discordAssetSmall = GetConvar("core:discordAssetSmall", "andyyy"),
discordActionText = GetConvar("core:discordActionText", "DISCORD"),
discordActionLink = GetConvar("discordActionLink", "https://discord.gg/Z9Mxu72zZ6"),
discordActionLink = GetConvar("core:discordActionLink", "https://discord.gg/Z9Mxu72zZ6"),
discordActionText2 = GetConvar("core:discordActionText2", "STORE"),
discordActionLink2 = GetConvar("core:discordActionLink2", "https://andyyy.tebex.io/category/fivem-scripts"),
disableVehicleAirControl = GetConvarInt("core:disableVehicleAirControl", 1) == 1,
@@ -15,7 +15,8 @@ Config = {
requireKeys = GetConvarInt("core:requireKeys", 1) == 1,
useInventoryForKeys = GetConvarInt("core:useInventoryForKeys", 1) == 1,
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.

View File

@@ -218,10 +218,10 @@ end)
RegisterCommand("getclothing", function(source, args, rawCommand)
local info = ""
for k, v in pairs(clothingComponents) do
info = ("%s\n%s = {\n drawable = %s,\n texture = %s\n},"):format(info, k, GetPedDrawableVariation(cache.ped, v), GetPedTextureVariation(cache.ped, v))
info = ("%s\n%s = { drawable = %s, texture = %s },"):format(info, k, GetPedDrawableVariation(cache.ped, v), GetPedTextureVariation(cache.ped, v))
end
for k, v in pairs(clothingProps) do
info = ("%s\n%s = {\n drawable = %s,\n texture = %s\n},"):format(info, k, GetPedPropIndex(cache.ped, v), GetPedPropTextureIndex(cache.ped, v))
info = ("%s\n%s = { drawable = %s, texture = %s },"):format(info, k, GetPedPropIndex(cache.ped, v), GetPedPropTextureIndex(cache.ped, v))
end
lib.setClipboard(info)
end, false)

View File

@@ -1,4 +1,14 @@
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",
groups = {"sahp", "lspd", "bcso"},
@@ -240,4 +250,52 @@ return {
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)
lib.callback.register("ND_Vehicles:getProps", function(netId)
local veh = getVehFromNetId(netId)
local function getProps(veh)
if not veh or not DoesEntityExist(veh) then return end
local props = lib.getVehicleProperties(veh)
local colorPrimary, colorSecondary = GetVehicleColours(veh)
if not props then return end
@@ -368,7 +369,18 @@ lib.callback.register("ND_Vehicles:getProps", function(netId)
props.className = vehicleClassNames[GetVehicleClass(veh)]
props.makeName = GetLabelText(GetMakeNameFromVehicleModel(props.model))
props.modelName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
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)
lib.callback.register("ND_Vehicles:getVehicleModelMakeLabel", function(model)
@@ -597,7 +609,7 @@ local function lockpickVehicle()
}
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)
local dificulty = dificulties[math.random(1, #dificulties)]
local success = lib.skillCheck(dificulty)

View File

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

View File

@@ -15,7 +15,7 @@ local moneyActions = {
}
lib.addCommand("setmoney", {
help = "Admin command, manage player money.",
help = "Admin command, set a players money.",
restricted = "group.admin",
params = {
{
@@ -164,7 +164,7 @@ lib.addCommand("setgroup", {
end)
lib.addCommand("skin", {
help = "Admin command, set player into character clothing menu.",
help = "Admin command, show character clothing menu for player.",
restricted = "group.admin",
params = {
{
@@ -178,7 +178,7 @@ lib.addCommand("skin", {
end)
lib.addCommand("character", {
help = "Admin command, set player into character selection menu.",
help = "Admin command, show character selection menu for player.",
restricted = "group.admin",
params = {
{
@@ -262,38 +262,22 @@ lib.addCommand("pay", {
end)
lib.addCommand("unlock", {
help = "Admin force unlock vehicles",
help = "Admin Command, force unlock a vehicle.",
restricted = "group.admin",
}, function(source, args, raw)
local ped = GetPlayerPed(source)
local playerVeh = GetVehiclePedIsIn(ped)
local coords = GetEntityCoords(ped)
local vehicles = GetAllVehicles()
local maxDistance = 2.0
local closestVehicle
local veh = lib.getClosestVehicle(coords, 2.5, true)
if not playerVeh or playerVeh == 0 or not DoesEntityExist(playerVeh) then
for i=1, #vehicles do
local vehicle = vehicles[i]
local vehicleCoords = GetEntityCoords(vehicle)
local distance = #(coords-vehicleCoords)
if not veh then return end
if distance < maxDistance then
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
local state = Entity(veh).state
state.hotwired = true
end
state.locked = false
end)
lib.addCommand("revive", {
help = "Admin command, revive player.",
help = "Admin command, revive a player.",
restricted = "group.admin",
params = {
{
@@ -309,60 +293,48 @@ lib.addCommand("revive", {
end)
lib.addCommand("dv", {
help = "Admin command, delete vehicles within the range.",
help = "Admin command, delete vehicles within the range or the closest.",
restricted = "group.admin",
params = {
{
name = "range",
type = "number",
help = "The range to select vehicles for deleteion from",
help = "Range to delete vehicles in",
optional = true
}
}
}, function(source, args, raw)
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 count = 0
local message = nil
local veh = lib.getClosestVehicle(coords, 3.0)
if args.range then
for _, veh in ipairs(GetAllVehicles()) do
local vehDist = #(GetEntityCoords(veh) - coords)
if vehDist < args.range then
local vehicles = lib.getNearbyVehicles(coords, args.range)
count = #vehicles
for i=1, count do
local veh = vehicles[i]
DeleteEntity(veh.vehicle)
end
elseif veh then
DeleteEntity(veh)
count += 1
end
end
return TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235},
multiline = true,
args = {"Staff action", ("deleted %d vehicles"):format(count)}
})
count = 1
end
local closest, dist
for _, veh in ipairs(GetAllVehicles()) do
local vehDist = #(GetEntityCoords(veh) - coords)
if vehDist < 5.0 and not closest or (dist and dist > vehDist) then
closest = veh
dist = vehDist
end
if count == 0 then
message = {"Staff action [dv]", "no vehicles found"}
elseif count == 1 then
message = {"Staff action [dv]", "deleted 1 vehicle"}
else
message = {"Staff action [dv]", ("deleted %d vehicles"):format(count)}
end
if not closest then return "no vehicle found nearby" end
DeleteEntity(closest)
TriggerClientEvent("chat:addMessage", source, {
color = {50, 100, 235},
multiline = true,
args = {"Staff action", "deleted 1 vehicle"}
args = message
})
end)
@@ -433,7 +405,7 @@ lib.addCommand("unfreeze", {
end)
lib.addCommand("vehicle", {
help = "Admin command, unfreeze a player.",
help = "Admin command, spawn a vehicle.",
restricted = "group.admin",
params = {
{
@@ -466,3 +438,45 @@ lib.addCommand("vehicle", {
Wait(100)
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
---@return table
function NDCore.getPlayer(src)

View File

@@ -24,8 +24,10 @@ Config = {
groups = json.decode(GetConvar("core:groups", "[]")),
admins = json.decode(GetConvar("core:admins", "[]")),
adminDiscordRoles = json.decode(GetConvar("core:adminDiscordRoles", "[]")),
groupRoles = json.decode(GetConvar("core:groupRoles", "[]")),
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)
@@ -42,6 +44,11 @@ local function getIdentifierList(src)
list[identifierType] = identifier
end
end
if Config.sv_lan then
list[Config.characterIdentifier] = NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)
end
return list
end
@@ -51,6 +58,10 @@ AddEventHandler("playerJoining", function(oldId)
PlayersInfo[src] = tempPlayersInfo[oldTempId]
tempPlayersInfo[oldTempId] = nil
if Config.sv_lan then
lib.addPrincipal(("player.%s"):format(src), "group.admin")
end
if Config.multiCharacter then return end
Wait(3000)
@@ -102,7 +113,7 @@ AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
if mainIdentifier and Config.discordBotToken ~= "false" and Config.discordGuildId ~= "false" then
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))
Wait(0)
end
@@ -111,6 +122,17 @@ AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
deferrals.update("Connecting...")
Wait(0)
if Config.sv_lan then
tempPlayersInfo[tempSrc] = {
identifiers = {
[Config.characterIdentifier] = "sv_lan"
},
discord = discordInfo
}
deferrals.done()
return
end
if mainIdentifier then
tempPlayersInfo[tempSrc] = {
identifiers = identifiers,
@@ -154,3 +176,10 @@ RegisterNetEvent("ND:playerEliminated", function(info)
deathInfo = info
})
end)
RegisterNetEvent("ND:updateClothing", function(clothing)
local src = source
local player = NDCore.getPlayer(src)
if not player or not clothing or type(clothing) ~= "table" then return end
player.setMetadata("clothing", clothing)
end)

View File

@@ -113,7 +113,8 @@ local function createCharacterTable(info)
TriggerEvent("ND:moneyChange", self.source, key, value, "set", reason)
end
end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), key)
TriggerEvent("ND:updateCharacter", self, key)
end
---@param key string|table
@@ -127,7 +128,8 @@ local function createCharacterTable(info)
else
self.metadata[key] = value
end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "metadata")
TriggerEvent("ND:updateCharacter", self, "metadata")
return self.metadata
end
@@ -223,7 +225,8 @@ local function createCharacterTable(info)
else
self.metadata.licenses = {license}
end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "metadata")
TriggerEvent("ND:updateCharacter", self, "metadata")
end
function self.getLicense(identifier)
@@ -269,11 +272,7 @@ local function createCharacterTable(info)
function self.notify(...)
if not self.source then return end
if GetResourceState("ModernHUD") == "started" then
TriggerClientEvent("ModernHUD:notify", self.source, ...)
elseif GetResourceState("ox_lib") == "started" then
TriggerClientEvent("ox_lib:notify", self.source, ...)
end
return true
end
@@ -310,6 +309,12 @@ local function createCharacterTable(info)
self.addGroup("admin")
end
end
for group, role in pairs(Config.groupRoles) do
if lib.table.contains(roles, role) then
self.addGroup(group)
end
end
end
for name, _ in pairs(self.groups) do
@@ -324,12 +329,15 @@ local function createCharacterTable(info)
---@param rank number
---@param isJob boolean
---@return boolean
function self.addGroup(name, rank, isJob)
function self.addGroup(name, rank, customGroup, isJob)
local groupRank = tonumber(rank) or 1
local groupInfo = Config.groups?[name]
local bossRank = groupInfo and groupInfo.minimumBossRank
local groupInfo = lib.table.deepclone(Config.groups?[name] or {})
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
for _, group in pairs(self.groups) do
group.isJob = nil
@@ -338,17 +346,21 @@ local function createCharacterTable(info)
self.groups[name] = {
name = name,
label = groupInfo and groupInfo.label or name,
rankName = groupInfo and groupInfo.ranks[groupRank] or groupRank,
label = groupInfo?.label or name,
rankName = groupInfo?.ranks?[groupRank] or groupRank,
rank = groupRank,
isJob = isJob,
isBoss = bossRank and groupRank >= bossRank
isBoss = bossRank and groupRank >= bossRank,
metadata = groupInfo.metadata or {}
}
if not isJob then
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "groups")
TriggerEvent("ND:updateCharacter", self, "groups")
end
lib.addPrincipal(self.source, ("group.%s"):format(name))
return self.groups[name]
end
@@ -369,7 +381,9 @@ local function createCharacterTable(info)
end
self.groups[name] = nil
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "groups")
TriggerEvent("ND:updateCharacter", self, "groups")
TriggerEvent("ND:groupRemoved", self, group)
lib.removePrincipal(self.source, ("group.%s"):format(name))
return group
end
@@ -379,12 +393,13 @@ local function createCharacterTable(info)
---@return boolean
function self.setJob(name, rank)
self.removeGroup(self.job)
local job = self.addGroup(name, rank, true)
local job = self.addGroup(name, rank, nil, true)
if job then
self.job = job.name
self.jobInfo = job
end
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self))
self.triggerEvent("ND:updateCharacter", removeCharacterFunctions(self), "job")
TriggerEvent("ND:updateCharacter", self, "job")
return job
end
@@ -411,7 +426,7 @@ end
---@param info table
---@return table
function NDCore.newCharacter(src, info)
local identifier = GetPlayerIdentifierByType(src, Config.characterIdentifier)
local identifier = NDCore.getPlayerIdentifierByType(src, Config.characterIdentifier)
if not identifier then return end
local charInfo = {
@@ -430,7 +445,7 @@ function NDCore.newCharacter(src, info)
inventory = info.inventory or {}
}
charInfo.id = MySQL.insert.await("INSERT INTO nd_characters (identifier, name, firstname, lastname, dob, gender, cash, bank, phonenumber, `groups`, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", {
charInfo.id = MySQL.insert.await("INSERT INTO nd_characters (identifier, name, firstname, lastname, dob, gender, cash, bank, phonenumber, `groups`, metadata, inventory) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", {
identifier,
charInfo.name,
charInfo.firstname,
@@ -441,7 +456,8 @@ function NDCore.newCharacter(src, info)
charInfo.bank,
charInfo.phonenumber,
json.encode(charInfo.groups),
json.encode(charInfo.metadata)
json.encode(charInfo.metadata),
json.encode(charInfo.inventory)
})
return createCharacterTable(charInfo)
@@ -452,7 +468,7 @@ end
function NDCore.fetchCharacter(id, src)
local result
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
result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ?", {id})
end
@@ -481,7 +497,7 @@ end
---@return table
function NDCore.fetchAllCharacters(src)
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
local info = result[i]

View File

@@ -1,6 +1,7 @@
local ox_inventory
local inventoryStarted = false
local spawnedPlayerVehicles = {}
local vehicleTypes = json.decode(GetResourceKvpString("ND_Core:vehTypes") or "[]")
NDCore.isResourceStarted("ox_inventory", function(started)
inventoryStarted = started
@@ -8,16 +9,24 @@ NDCore.isResourceStarted("ox_inventory", function(started)
ox_inventory = exports.ox_inventory
end)
local function getVehicleType(model)
local tempVehicle = CreateVehicle(model, 0, 0, 0, 0, true, true)
local function getVehicleType(coords, model)
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()
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
local entityType = GetVehicleType(tempVehicle)
local vehType = GetVehicleType(tempVehicle)
DeleteEntity(tempVehicle)
return entityType
vehicleTypes[model] = vehType
SetResourceKvp("ND_Core:vehTypes", json.encode(vehicleTypes))
return vehType
end
local function generatePlate()
@@ -99,6 +108,15 @@ function NDCore.getVehicle(entity)
DeleteEntity(entity)
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
---@param props table
function self.setProperties(props)
@@ -156,13 +174,22 @@ function NDCore.getVehicle(entity)
function self.setMetadata(key, value)
self.metadata[key] = value
if DoesEntityExist(entity) then
local state = Entity(self.entity).state
local metadata = state.metadata
metadata[key] = value
state.metadata = metadata
if not state.metadata then
state.metadata = self.metadata
else
state.metadata[key] = value
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})
end
@@ -253,14 +280,14 @@ function NDCore.createVehicle(info)
end
local model = info.model or properties.model
local vehType = getVehicleType(model)
local vehType = getVehicleType(spawnCoords, model)
if not vehType then
return Citizen.Trace("NDCore.createVehicle", "vehType not found")
end
local veh = CreateVehicleServerSetter(model, vehType, spawnCoords.x, spawnCoords.y, spawnCoords.z, spawnCoords.w)
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
return Citizen.Trace("NDCore.createVehicle", "vehicle entity doesn't exist")
end
@@ -411,7 +438,8 @@ function NDCore.spawnOwnedVehicle(source, vehicleId, coords, heading)
if not player then return end
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})
@@ -701,6 +729,11 @@ RegisterNetEvent("ND_Vehicles:takeVehicle", function(vehId, locations)
local vehicle = NDCore.getVehicleById(vehId)
local player = NDCore.getPlayer(src)
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
local reclaimPrice = vehicle.metadata.impoundReclaimPrice or 200
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})
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)
lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src)
@@ -730,3 +759,30 @@ lib.callback.register("ND_Vehicles:getOwnedVehicles", function(src)
if not player then return end
return NDCore.getVehicles(player.id)
end)
AddEventHandler("ND:characterLoaded", function(player)
local ownedExistingVehicles = {}
local ownedVehicles = NDCore.getVehicles(player.id)
local vehicles = GetAllVehicles()
local vehiclesToImpound = {}
for i=1, #vehicles do
local veh = vehicles[i]
local state = Entity(veh).state
if state.owner == player.id then
ownedExistingVehicles[#ownedExistingVehicles+1] = state.id
end
end
for i=1, #ownedVehicles do
local veh = ownedVehicles[i]
if veh and not veh.stored and not veh.impounded and not lib.table.contains(ownedExistingVehicles, veh.id) then
vehiclesToImpound[#vehiclesToImpound+1] = veh.id
end
end
if #vehiclesToImpound == 0 then return end
local query = ("UPDATE nd_vehicles SET impounded = ? WHERE owner = ? AND id IN (%s)"):format(table.concat(vehiclesToImpound, ", "))
MySQL.rawExecute(query, {1, player.id})
end)