mirror of
https://github.com/ND-Framework/ND_Core.git
synced 2026-08-17 05:56:01 +01:00
Start of ND 2.0
This commit is contained in:
@@ -4,21 +4,29 @@ end)
|
|||||||
|
|
||||||
-- updates the money on the client.
|
-- updates the money on the client.
|
||||||
RegisterNetEvent("ND:updateMoney", function(cash, bank)
|
RegisterNetEvent("ND:updateMoney", function(cash, bank)
|
||||||
NDCore.SelectedCharacter.cash = cash
|
NDCore.player.cash = cash
|
||||||
NDCore.SelectedCharacter.bank = bank
|
NDCore.player.bank = bank
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Sets main character.
|
-- Sets main character.
|
||||||
RegisterNetEvent("ND:setCharacter", function(character)
|
RegisterNetEvent("ND:setCharacter", function(character)
|
||||||
NDCore.SelectedCharacter = character
|
NDCore.player = character
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Update main character info.
|
-- Update main character info.
|
||||||
RegisterNetEvent("ND:updateCharacter", function(character)
|
RegisterNetEvent("ND:updateCharacter", function(character)
|
||||||
NDCore.SelectedCharacter = character
|
NDCore.player = character
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Updates last lcoation.
|
-- Updates last lcoation.
|
||||||
RegisterNetEvent("ND:updateLastLocation", function(location)
|
RegisterNetEvent("ND:updateLastLocation", function(location)
|
||||||
NDCore.SelectedCharacter.lastLocation = location
|
if not NDCore.player then return end
|
||||||
|
NDCore.player.lastLocation = location
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Enable pvp for players.
|
||||||
|
AddEventHandler("playerSpawned", function()
|
||||||
|
print("^0ND Framework support discord: ^5https://discord.gg/Z9Mxu72zZ6")
|
||||||
|
SetCanAttackFriendly(PlayerPedId(), true, false)
|
||||||
|
NetworkSetFriendlyFireOption(true)
|
||||||
|
end)
|
||||||
@@ -1,19 +1,6 @@
|
|||||||
function GetCoreObject()
|
function NDCore.GetPlayersFromCoords(distance, coords)
|
||||||
return NDCore
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.Functions.GetSelectedCharacter()
|
|
||||||
return NDCore.SelectedCharacter
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.Functions.GetCharacters()
|
|
||||||
return NDCore.Characters
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function NDCore.Functions.GetPlayersFromCoords(distance, coords)
|
|
||||||
if coords then
|
if coords then
|
||||||
coords = type(coords) == 'table' and vec3(coords.x, coords.y, coords.z) or coords
|
coords = type(coords) == "table" and vec3(coords.x, coords.y, coords.z) or coords
|
||||||
else
|
else
|
||||||
coords = GetEntityCoords(PlayerPedId())
|
coords = GetEntityCoords(PlayerPedId())
|
||||||
end
|
end
|
||||||
@@ -30,51 +17,3 @@ function NDCore.Functions.GetPlayersFromCoords(distance, coords)
|
|||||||
end
|
end
|
||||||
return closePlayers
|
return closePlayers
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Callbacks are licensed under LGPL v3.0
|
|
||||||
-- <https://github.com/overextended/ox_lib>
|
|
||||||
NDCore.callback = {}
|
|
||||||
local events = {}
|
|
||||||
|
|
||||||
RegisterNetEvent("ND:callbacks", function(key, ...)
|
|
||||||
local cb = events[key]
|
|
||||||
return cb and cb(...)
|
|
||||||
end)
|
|
||||||
|
|
||||||
local function triggerCallback(_, name, cb, ...)
|
|
||||||
local key = ("%s:%s"):format(name, math.random(0, 100000))
|
|
||||||
TriggerServerEvent(("ND:%s_cb"):format(name), key, ...)
|
|
||||||
|
|
||||||
local promise = not cb and promise.new()
|
|
||||||
|
|
||||||
events[key] = function(response, ...)
|
|
||||||
response = { response, ... }
|
|
||||||
events[key] = nil
|
|
||||||
|
|
||||||
if promise then
|
|
||||||
return promise:resolve(response)
|
|
||||||
end
|
|
||||||
|
|
||||||
if cb then
|
|
||||||
cb(table.unpack(response))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if promise then
|
|
||||||
return table.unpack(Citizen.Await(promise))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
setmetatable(NDCore.callback, {
|
|
||||||
__call = triggerCallback
|
|
||||||
})
|
|
||||||
|
|
||||||
function NDCore.callback.await(name, ...)
|
|
||||||
return triggerCallback(nil, name, false, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.callback.register(name, callback)
|
|
||||||
RegisterNetEvent(("ND:%s_cb"):format(name), function(key, ...)
|
|
||||||
TriggerServerEvent("ND:callbacks", key, callback(...))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -1,54 +1,36 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
CreateThread(function()
|
||||||
|
SetDiscordAppId(Config.discordAppId)
|
||||||
NDCore = {}
|
SetDiscordRichPresenceAsset(Config.discordAsset)
|
||||||
NDCore.SelectedCharacter = nil
|
SetDiscordRichPresenceAssetSmall(Config.discordAssetSmall)
|
||||||
NDCore.Characters = {}
|
SetDiscordRichPresenceAction(0, Config.discordActionText, Config.discordActionLink)
|
||||||
NDCore.Functions = {}
|
SetDiscordRichPresenceAction(1, Config.discordActionText2, Config.discordActionLink2)
|
||||||
NDCore.Config = config
|
local presenceText = ("Playing: %s"):format(Config.serverName)
|
||||||
|
while true do
|
||||||
-- discord rich precense will show on a users profile.
|
if NDCore.player then
|
||||||
if config.enableRichPresence then
|
local presence = ("Playing: %s as % %"):format(Config.serverName, NDCore.player.firstname, NDCore.player.lastname)
|
||||||
Citizen.CreateThread(function()
|
local presenceTextSmall = ("Playing as: %s %s"):format(NDCore.player.firstname, NDCore.player.lastname)
|
||||||
while true do
|
SetRichPresence(presence)
|
||||||
if NDCore.SelectedCharacter then
|
SetDiscordRichPresenceAssetText(presenceText)
|
||||||
SetDiscordAppId(config.appId)
|
SetDiscordRichPresenceAssetSmallText(presenceTextSmall)
|
||||||
SetRichPresence(" Playing : " .. config.serverName .. " as " .. NDCore.SelectedCharacter.firstName .. " " .. NDCore.SelectedCharacter.lastName)
|
|
||||||
SetDiscordRichPresenceAsset(config.largeLogo)
|
|
||||||
SetDiscordRichPresenceAssetText("Playing: " .. config.serverName)
|
|
||||||
SetDiscordRichPresenceAssetSmall(config.smallLogo)
|
|
||||||
SetDiscordRichPresenceAssetSmallText("Playing as: " .. NDCore.SelectedCharacter.firstName .. " " .. NDCore.SelectedCharacter.lastName)
|
|
||||||
SetDiscordRichPresenceAction(0, config.firstButtonName, config.firstButtonLink)
|
|
||||||
SetDiscordRichPresenceAction(1, config.secondButtonName, config.secondButtonLink)
|
|
||||||
end
|
|
||||||
Citizen.Wait(config.updateIntervall * 1000)
|
|
||||||
end
|
end
|
||||||
end)
|
Wait(60000)
|
||||||
end
|
|
||||||
|
|
||||||
-- show server name, first name, last name, and the amount of money the character has in the pause menu.
|
|
||||||
if config.customPauseMenu then
|
|
||||||
Citizen.CreateThread(function()
|
|
||||||
while true do
|
|
||||||
Citizen.Wait(0)
|
|
||||||
if NDCore.SelectedCharacter then
|
|
||||||
if IsPauseMenuActive() then
|
|
||||||
BeginScaleformMovieMethodOnFrontendHeader("SET_HEADING_DETAILS")
|
|
||||||
AddTextEntry("FE_THDR_GTAO", config.serverName)
|
|
||||||
ScaleformMovieMethodAddParamPlayerNameString(NDCore.SelectedCharacter.firstName .. " " .. NDCore.SelectedCharacter.lastName)
|
|
||||||
PushScaleformMovieFunctionParameterString("Cash: $" .. tostring(NDCore.SelectedCharacter.cash))
|
|
||||||
PushScaleformMovieFunctionParameterString("Bank: $" .. tostring(NDCore.SelectedCharacter.bank))
|
|
||||||
EndScaleformMovieMethod()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Enables pvp if it's selected in the config.
|
|
||||||
AddEventHandler("playerSpawned", function()
|
|
||||||
if config.enablePVP then
|
|
||||||
SetCanAttackFriendly(PlayerPedId(), true, false)
|
|
||||||
NetworkSetFriendlyFireOption(true)
|
|
||||||
end
|
end
|
||||||
print("^0This framework is created by ^5Andyyy#7666 ^0for support you can join the ^5discord: ^0https://discord.gg/Z9Mxu72zZ6")
|
end)
|
||||||
end)
|
|
||||||
|
CreateThread(function()
|
||||||
|
AddTextEntry("FE_THDR_GTAO", Config.serverName)
|
||||||
|
local sleep = 500
|
||||||
|
while true do
|
||||||
|
Wait(sleep)
|
||||||
|
if NDCore.player and IsPauseMenuActive() then
|
||||||
|
sleep = 0
|
||||||
|
BeginScaleformMovieMethodOnFrontendHeader("SET_HEADING_DETAILS")
|
||||||
|
ScaleformMovieMethodAddParamPlayerNameString(("%s %s"):format(NDCore.player.firstname, NDCore.player.lastname))
|
||||||
|
PushScaleformMovieFunctionParameterString(("Cash: $%d"):format(NDCore.player.cash))
|
||||||
|
PushScaleformMovieFunctionParameterString(("Bank: $%d"):format(NDCore.player.bank))
|
||||||
|
EndScaleformMovieMethod()
|
||||||
|
elseif sleep == 0 then
|
||||||
|
sleep = 500
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
|
||||||
|
|
||||||
config = {
|
|
||||||
serverName = "Andy's Development",
|
|
||||||
characterLimit = 15, -- How many characters can a player create.
|
|
||||||
customPauseMenu = true, -- A custom pause menu will display your money, characters name and the server name in the pause menu.
|
|
||||||
enablePVP = true, -- pvp allows doing damage to other players.
|
|
||||||
|
|
||||||
-- Money related
|
|
||||||
startingCash = 2500, -- default cash the character will start with if the character creator doesn't specify it.
|
|
||||||
startingBank = 8000,-- default money in the bank account the character will start with if the character creator doesn't specify it.
|
|
||||||
|
|
||||||
-- If you'd like to whitelist certain roles on discord then set this to true and add role ids.
|
|
||||||
enableDiscordWhitelist = false,
|
|
||||||
notWhitelistedMessage = "You're not allowlisted in this server please join our discord to apply for a allowlist: https://discord.gg/Z9Mxu72zZ6",
|
|
||||||
whitelistRoles = {
|
|
||||||
"872921520719142932"
|
|
||||||
},
|
|
||||||
|
|
||||||
-- These are admins roles that will give a user permission to admin commands and more.
|
|
||||||
adminRoles = {
|
|
||||||
"872921520719142932"
|
|
||||||
},
|
|
||||||
|
|
||||||
-- Discord Rich presence
|
|
||||||
enableRichPresence = true,
|
|
||||||
updateIntervall = 60, -- how many seconds of delay until it updates status.
|
|
||||||
appId = 858146067018416128,
|
|
||||||
largeLogo = "andyyy",
|
|
||||||
smallLogo = "andyyy",
|
|
||||||
firstButtonName = "DISCORD",
|
|
||||||
firstButtonLink = "https://discord.gg/Z9Mxu72zZ6",
|
|
||||||
secondButtonName = "TEBEX",
|
|
||||||
secondButtonLink = "https://andyyy.tebex.io/category/fivem-scripts",
|
|
||||||
|
|
||||||
|
|
||||||
-- Groups can be gangs, jobs, subdivisions, etc.
|
|
||||||
groups = {
|
|
||||||
["Ballas"] = {
|
|
||||||
"Member", -- rank 1
|
|
||||||
"Boss" -- rank 2
|
|
||||||
},
|
|
||||||
["SWAT"] = {
|
|
||||||
"Member", -- rank 1
|
|
||||||
"Sniper", -- rank 2
|
|
||||||
"Team lead", -- rank 3
|
|
||||||
"Commander" -- rank 4
|
|
||||||
},
|
|
||||||
["SAHP"] = {
|
|
||||||
"Trooper",
|
|
||||||
"Senior Trooper",
|
|
||||||
"Corporal",
|
|
||||||
"Sergeant",
|
|
||||||
"Lieutenant",
|
|
||||||
"Cheif"
|
|
||||||
},
|
|
||||||
["LSPD"] = {
|
|
||||||
"Officer",
|
|
||||||
"Senior officer",
|
|
||||||
"Corporal",
|
|
||||||
"Sergeant",
|
|
||||||
"Lieutenant",
|
|
||||||
"Cheif"
|
|
||||||
},
|
|
||||||
["BCSO"] = {
|
|
||||||
"Deputy",
|
|
||||||
"Senior Deputy",
|
|
||||||
"Corporal",
|
|
||||||
"Sergeant",
|
|
||||||
"Lieutenant",
|
|
||||||
"Cheif"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
|
||||||
|
|
||||||
server_config = {
|
|
||||||
discordServerToken = "OTAwODg1MDMxMDQ2Nzc0ODQ1.GU1TSC.Ed8D2_wcU-UQ1vZhe1khahgV8J3hLahOp4N1D8", -- discord bot token for permissions
|
|
||||||
guildId = "872496972454592523", -- discord guild id
|
|
||||||
}
|
|
||||||
@@ -1,39 +1,25 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
||||||
|
|
||||||
author "Andyyy#7666, N1K0#0001"
|
author "Andyyy#7666"
|
||||||
description "ND Framework Core"
|
description "ND Framework Core"
|
||||||
version "1.0.3"
|
version "2.0.0"
|
||||||
|
|
||||||
fx_version "cerulean"
|
fx_version "cerulean"
|
||||||
game "gta5"
|
game "gta5"
|
||||||
lua54 "yes"
|
lua54 "yes"
|
||||||
|
|
||||||
shared_scripts {
|
shared_scripts {
|
||||||
"config_client.lua",
|
"init.lua"
|
||||||
"shared/main.lua"
|
|
||||||
}
|
}
|
||||||
client_scripts {
|
client_scripts {
|
||||||
"client/main.lua",
|
|
||||||
"client/functions.lua",
|
"client/functions.lua",
|
||||||
"client/events.lua",
|
"client/events.lua",
|
||||||
"shared/import.lua"
|
"client/main.lua"
|
||||||
}
|
}
|
||||||
server_scripts {
|
server_scripts {
|
||||||
"@oxmysql/lib/MySQL.lua",
|
"@oxmysql/lib/MySQL.lua",
|
||||||
"config_server.lua",
|
|
||||||
"server/main.lua",
|
"server/main.lua",
|
||||||
"server/functions.lua",
|
"server/player.lua"
|
||||||
"server/events.lua",
|
|
||||||
"server/commands.lua",
|
|
||||||
"shared/import.lua"
|
|
||||||
}
|
|
||||||
|
|
||||||
exports {
|
|
||||||
"GetCoreObject"
|
|
||||||
}
|
|
||||||
|
|
||||||
server_exports {
|
|
||||||
"GetCoreObject"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependency "oxmysql"
|
dependency "oxmysql"
|
||||||
|
|||||||
16
init.lua
Normal file
16
init.lua
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Config = {
|
||||||
|
serverName = GetConvar("core:serverName", "Unconfigured ND-Core Server"),
|
||||||
|
discordInvite = GetConvar("core:discordInvite", "https://discord.gg/Z9Mxu72zZ6"),
|
||||||
|
discordAppId = GetConvar("core:discordAppId", "858146067018416128"),
|
||||||
|
discordAsset = GetConvar("core:discordAsset", "andyyy"),
|
||||||
|
discordAssetSmall = GetConvar("core:discordAssetSmall", "andyyy"),
|
||||||
|
discordActionText = GetConvar("core:discordActionText", "DISCORD"),
|
||||||
|
discordActionLink = GetConvar("discordActionLink", "https://discord.gg/Z9Mxu72zZ6"),
|
||||||
|
discordActionText2 = GetConvar("core:discordActionText2", "STORE"),
|
||||||
|
discordActionLink2 = GetConvar("core:discordActionLink2", "https://andyyy.tebex.io/category/fivem-scripts"),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NDCore = {
|
||||||
|
config = Config
|
||||||
|
}
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
NDCore.Functions.AddCommand("setmoney", "Admin command, manage player money.", function(source, args, rawCommand)
|
|
||||||
if not NDCore.Functions.IsPlayerAdmin(source) then return end
|
|
||||||
|
|
||||||
local target = tonumber(args[1])
|
|
||||||
local action = args[2]
|
|
||||||
local moneyType = args[3]:lower()
|
|
||||||
local amount = tonumber(args[4])
|
|
||||||
|
|
||||||
if not target or GetPlayerPing(target) == 0 then return end
|
|
||||||
if action ~= "remove" and action ~= "add" and action ~= "set" then return end
|
|
||||||
if moneyType ~= "bank" and moneyType ~= "cash" then return end
|
|
||||||
|
|
||||||
if action == "remove" then
|
|
||||||
if not amount or amount < 1 then return end
|
|
||||||
NDCore.Functions.DeductMoney(amount, target, moneyType, "Server staff action.")
|
|
||||||
elseif action == "add" then
|
|
||||||
if not amount or amount < 1 then return end
|
|
||||||
NDCore.Functions.AddMoney(amount, target, moneyType, "Server staff action.")
|
|
||||||
elseif action == "set" then
|
|
||||||
local character = NDCore.Functions.GetPlayer(target)
|
|
||||||
NDCore.Functions.SetPlayerData(character.id, moneyType, amount, "Server staff action.")
|
|
||||||
end
|
|
||||||
end, true, {
|
|
||||||
{ name="player", help="Player server id" },
|
|
||||||
{ name="action", help="remove/add/set" },
|
|
||||||
{ name="type", help="bank/cash" },
|
|
||||||
{ name="amount" }
|
|
||||||
})
|
|
||||||
|
|
||||||
NDCore.Functions.AddCommand("setjob", "Admin command, set player job.", function(source, args, rawCommand)
|
|
||||||
if not NDCore.Functions.IsPlayerAdmin(source) then
|
|
||||||
return {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "you don't have access to this command."}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local target = tonumber(args[1])
|
|
||||||
if not target or GetPlayerPing(target) == 0 then
|
|
||||||
return {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "target player not found."}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local job = args[2]
|
|
||||||
if not job then
|
|
||||||
return {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "job required."}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local character = NDCore.Functions.GetPlayer(target)
|
|
||||||
NDCore.Functions.SetPlayerJob(character.id, job, args[3])
|
|
||||||
return {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", GetPlayerName(target) .. " job set to " .. job .. (args[3] and " rank " .. args[3] or " rank 1.")}
|
|
||||||
}
|
|
||||||
end, false, {
|
|
||||||
{ name="player", help="Player server id" },
|
|
||||||
{ name="job name" },
|
|
||||||
{ name="rank", help="This should be a number, default value is 1." }
|
|
||||||
})
|
|
||||||
|
|
||||||
NDCore.Functions.AddCommand("setgroup", "Admin command, set player group.", function(source, args, rawCommand)
|
|
||||||
if not NDCore.Functions.IsPlayerAdmin(source) then return end
|
|
||||||
|
|
||||||
local target = tonumber(args[1])
|
|
||||||
if not target or GetPlayerPing(target) == 0 then
|
|
||||||
return {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "target player not found."}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local group = args[3]
|
|
||||||
if not group then
|
|
||||||
return {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "group required."}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local character = NDCore.Functions.GetPlayer(target)
|
|
||||||
if args[2] == "remove" then
|
|
||||||
NDCore.Functions.RemovePlayerFromGroup(character.id, group)
|
|
||||||
return {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", GetPlayerName(target) .. " removed from " .. group}
|
|
||||||
}
|
|
||||||
elseif args[2] == "add" then
|
|
||||||
local rank = args[4]
|
|
||||||
NDCore.Functions.SetPlayerToGroup(character.id, group, rank)
|
|
||||||
return {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", GetPlayerName(target) .. " added to " .. group .. (rank and " rank " .. rank or " rank 1.")}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end, false, {
|
|
||||||
{ name="player", help="Player server id" },
|
|
||||||
{ name="action", help="remove/add"},
|
|
||||||
{ name="group", help="Group name, make sure it's correct or it won't work."},
|
|
||||||
{ name="rank", help="This should be a number, default value is 1 (not required if removing)." }
|
|
||||||
})
|
|
||||||
|
|
||||||
NDCore.Functions.AddCommand("pay", "give cash to a nearby player", function(source, args, rawCommand)
|
|
||||||
local amount = args[1]
|
|
||||||
if not amount or amount == 0 then return end
|
|
||||||
NDCore.Functions.GiveCashToNearbyPlayer(source, amount)
|
|
||||||
return {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", amount .. " paid."}
|
|
||||||
}
|
|
||||||
end, true, {
|
|
||||||
{ name="Amount" },
|
|
||||||
})
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
|
||||||
|
|
||||||
-- Check if discord is connected, and if whitelist is enabled then it will only allow you to join if you have the roles.
|
|
||||||
AddEventHandler("playerConnecting", function(name, setKickReason, deferrals)
|
|
||||||
local player = source
|
|
||||||
local discordIdentifier = NDCore.Functions.GetPlayerIdentifierFromType("discord", player)
|
|
||||||
|
|
||||||
deferrals.defer()
|
|
||||||
Wait(0)
|
|
||||||
deferrals.update("Connecting to discord.")
|
|
||||||
Wait(0)
|
|
||||||
|
|
||||||
if not discordIdentifier then
|
|
||||||
deferrals.done("Your discord isn't connected to FiveM, make sure discord is open and restart FiveM.")
|
|
||||||
else
|
|
||||||
if config.enableDiscordWhitelist then
|
|
||||||
local discordUserId = discordIdentifier:gsub("discord:", "")
|
|
||||||
local discordInfo = NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
|
||||||
for _, whitelistRole in pairs(config.whitelistRoles) do
|
|
||||||
if whitelistRole == 0 or whitelistRole == "0" or (discordInfo and discordInfo.roles[whitelistRole]) then
|
|
||||||
deferrals.done()
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
deferrals.done(config.notWhitelistedMessage)
|
|
||||||
else
|
|
||||||
deferrals.done()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Getting all the characters the player has and returning them to the client.
|
|
||||||
RegisterNetEvent("ND:GetCharacters", function()
|
|
||||||
local player = source
|
|
||||||
TriggerClientEvent("ND:returnCharacters", player, NDCore.Functions.GetPlayerCharacters(player))
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Creating a new character.
|
|
||||||
RegisterNetEvent("ND:newCharacter", function(newCharacter)
|
|
||||||
local player = source
|
|
||||||
NDCore.Functions.CreateCharacter(player, newCharacter.firstName, newCharacter.lastName, newCharacter.dob, newCharacter.gender, newCharacter.cash, newCharacter.bank)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Update the character info when edited.
|
|
||||||
RegisterNetEvent("ND:editCharacter", function(newCharacter)
|
|
||||||
local player = source
|
|
||||||
local characters = NDCore.Functions.GetPlayerCharacters(player)
|
|
||||||
if not characters[newCharacter.id] then return end
|
|
||||||
NDCore.Functions.UpdateCharacterData(newCharacter.id, newCharacter.firstName, newCharacter.lastName, newCharacter.dob, newCharacter.gender)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Delete character from database.
|
|
||||||
RegisterNetEvent("ND:deleteCharacter", function(characterId)
|
|
||||||
local player = source
|
|
||||||
local characters = NDCore.Functions.GetPlayerCharacters(player)
|
|
||||||
if not characters[characterId] then return end
|
|
||||||
NDCore.Functions.DeleteCharacter(characterId)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- add a player to the table.
|
|
||||||
RegisterNetEvent("ND:setCharacterOnline", function(id)
|
|
||||||
local player = source
|
|
||||||
local characters = NDCore.Functions.GetPlayerCharacters(player)
|
|
||||||
if not characters[id] then return end
|
|
||||||
NDCore.Functions.SetActiveCharacter(player, id)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Update the characters clothes.
|
|
||||||
RegisterNetEvent("ND:updateClothes", function(clothing)
|
|
||||||
local player = source
|
|
||||||
local character = NDCore.Players[player]
|
|
||||||
NDCore.Functions.SetPlayerData(character.id, "clothing", clothing)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Disconnecting a player
|
|
||||||
RegisterNetEvent("ND:exitGame", function()
|
|
||||||
local player = source
|
|
||||||
DropPlayer(player, "Disconnected.")
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Remove player from NDCore.Players table when they leave.
|
|
||||||
AddEventHandler("playerDropped", function()
|
|
||||||
local player = source
|
|
||||||
local character = NDCore.Players[player]
|
|
||||||
if character then
|
|
||||||
local ped = GetPlayerPed(player)
|
|
||||||
local lastLocation = GetEntityCoords(ped)
|
|
||||||
NDCore.Functions.UpdateLastLocation(character.id, {x = lastLocation.x, y = lastLocation.y, z = lastLocation.z})
|
|
||||||
end
|
|
||||||
TriggerEvent("ND:characterUnloaded", player, character)
|
|
||||||
character = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Get player discord info on join.
|
|
||||||
AddEventHandler("playerJoining", function()
|
|
||||||
local src = source
|
|
||||||
|
|
||||||
local discordUserId = NDCore.Functions.GetPlayerIdentifierFromType("discord", src):gsub("discord:", "")
|
|
||||||
local discordInfo = NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
|
||||||
|
|
||||||
NDCore.PlayersDiscordInfo[src] = discordInfo
|
|
||||||
end)
|
|
||||||
|
|
||||||
AddEventHandler("onResourceStart", function(resourceName)
|
|
||||||
if (GetCurrentResourceName() ~= resourceName) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
Wait(1000)
|
|
||||||
|
|
||||||
if not next(NDCore.PlayersDiscordInfo) then
|
|
||||||
for _, playerId in ipairs(GetPlayers()) do
|
|
||||||
local discordUserId = NDCore.Functions.GetPlayerIdentifierFromType("discord", playerId):gsub("discord:", "")
|
|
||||||
local discordInfo = NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
|
||||||
NDCore.PlayersDiscordInfo[tonumber(playerId)] = discordInfo
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
@@ -1,766 +0,0 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
|
||||||
|
|
||||||
-- Get an active players character data.
|
|
||||||
function NDCore.Functions.GetPlayer(player)
|
|
||||||
return NDCore.Players[player]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get all active players character data.
|
|
||||||
function NDCore.Functions.GetPlayers(getBy, value)
|
|
||||||
if not getBy or not value then
|
|
||||||
return NDCore.Players
|
|
||||||
end
|
|
||||||
local players = {}
|
|
||||||
|
|
||||||
if getBy == "groups" then
|
|
||||||
for player, playerInfo in pairs(NDCore.Players) do
|
|
||||||
if playerInfo.data.groups then
|
|
||||||
local valueGroup = value:lower()
|
|
||||||
for group, _ in pairs(playerInfo.data.groups) do
|
|
||||||
if group and group:lower() == valueGroup then
|
|
||||||
players[player] = playerInfo
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for player, playerInfo in pairs(NDCore.Players) do
|
|
||||||
if playerInfo[getBy] == value then
|
|
||||||
players[player] = playerInfo
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return players
|
|
||||||
end
|
|
||||||
|
|
||||||
local discordErrors = {
|
|
||||||
[400] = "improper http request",
|
|
||||||
[401] = "Discord bot token might be missing or incorrect",
|
|
||||||
[404] = "user might not be in server.",
|
|
||||||
[429] = "Discord bot rate limited."
|
|
||||||
}
|
|
||||||
-- Used to retrive the players discord server nickname, discord name and tag, and the roles.
|
|
||||||
function NDCore.Functions.GetUserDiscordInfo(discordUserId)
|
|
||||||
local data
|
|
||||||
local timeout = 0
|
|
||||||
PerformHttpRequest("https://discordapp.com/api/guilds/" .. server_config.guildId .. "/members/" .. discordUserId, function(errorCode, resultData, resultHeaders)
|
|
||||||
if errorCode ~= 200 then
|
|
||||||
print("Error: " .. errorCode .. " " .. discordErrors[errorCode])
|
|
||||||
end
|
|
||||||
local result = json.decode(resultData)
|
|
||||||
local roles = {}
|
|
||||||
local nickname = ""
|
|
||||||
local tag = ""
|
|
||||||
if result and result.roles then
|
|
||||||
for _, roleId in pairs(result.roles) do
|
|
||||||
roles[roleId] = roleId
|
|
||||||
end
|
|
||||||
if result.nick then
|
|
||||||
nickname = result.nick
|
|
||||||
end
|
|
||||||
if result.user and result.user.username and result.user.discriminator then
|
|
||||||
tag = tostring(result.user.username) .. "#" .. tostring(result.user.discriminator)
|
|
||||||
end
|
|
||||||
data = {
|
|
||||||
nickname = nickname,
|
|
||||||
discordTag = tag,
|
|
||||||
roles = roles
|
|
||||||
}
|
|
||||||
return
|
|
||||||
end
|
|
||||||
data = {
|
|
||||||
nickname = nickname,
|
|
||||||
discordTag = tag,
|
|
||||||
roles = roles
|
|
||||||
}
|
|
||||||
end, "GET", "", {["Content-Type"] = "application/json", ["Authorization"] = "Bot " .. server_config.discordServerToken})
|
|
||||||
while not data do
|
|
||||||
Wait(1000)
|
|
||||||
timeout = timeout + 1
|
|
||||||
if timeout > 5 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return data
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get player any identifier, available types: steam, license, xbl, ip, discord, live.
|
|
||||||
function NDCore.Functions.GetPlayerIdentifierFromType(type, player)
|
|
||||||
local identifierCount = GetNumPlayerIdentifiers(player)
|
|
||||||
for count = 0, identifierCount do
|
|
||||||
local identifier = GetPlayerIdentifier(player, count)
|
|
||||||
if identifier and string.find(identifier, type) then
|
|
||||||
return identifier
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This will return the server id and ND player data of a nearby player.
|
|
||||||
function NDCore.Functions.GetNearbyPedToPlayer(player)
|
|
||||||
local pedCoords = GetEntityCoords(GetPlayerPed(player))
|
|
||||||
for targetId, targetInfo in pairs(NDCore.Players) do
|
|
||||||
local targetCoords = GetEntityCoords(GetPlayerPed(targetId))
|
|
||||||
if #(pedCoords - targetCoords) < 2.0 and targetId ~= player then
|
|
||||||
return targetId, targetInfo
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update the players money on the client kinda like a refresh.
|
|
||||||
function NDCore.Functions.UpdateMoney(player)
|
|
||||||
local player = tonumber(player)
|
|
||||||
local result = MySQL.query.await("SELECT cash, bank FROM characters WHERE character_id = ? LIMIT 1", {NDCore.Players[player].id})
|
|
||||||
if result then
|
|
||||||
local cash = result[1].cash
|
|
||||||
local bank = result[1].bank
|
|
||||||
NDCore.Players[player].cash = cash
|
|
||||||
NDCore.Players[player].bank = bank
|
|
||||||
TriggerClientEvent("ND:updateMoney", player, cash, bank)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Transfer money from one players bank account to another.
|
|
||||||
function NDCore.Functions.TransferBank(amount, player, target, descriptionSender, descriptionReceiver)
|
|
||||||
local amount = tonumber(amount)
|
|
||||||
local player = tonumber(player)
|
|
||||||
local target = tonumber(target)
|
|
||||||
if player == target then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "You can't send money to yourself."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
elseif GetPlayerPing(target) == 0 then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "That player does not exist."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
elseif amount <= 0 then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "You can't send that amount."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
elseif NDCore.Players[player].bank < amount then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "You don't have enough money."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = bank - ? WHERE character_id = ?", {amount, NDCore.Players[player].id})
|
|
||||||
NDCore.Functions.UpdateMoney(player)
|
|
||||||
TriggerEvent("ND:moneyChange", player, "bank", amount, "remove", descriptionSender or "Transfer")
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", "You paid " .. NDCore.Players[target].firstName .. " " .. NDCore.Players[target].lastName .. " $" .. amount .. "."}
|
|
||||||
})
|
|
||||||
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = bank + ? WHERE character_id = ?", {amount, NDCore.Players[target].id})
|
|
||||||
NDCore.Functions.UpdateMoney(target)
|
|
||||||
TriggerEvent("ND:moneyChange", target, "bank", amount, "add", descriptionReceiver or "Transfer")
|
|
||||||
TriggerClientEvent("chat:addMessage", target, {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", NDCore.Players[player].firstName .. " " .. NDCore.Players[player].lastName .. " sent you $" .. amount .. "."}
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Give cash from one players wallet to another.
|
|
||||||
function NDCore.Functions.GiveCash(amount, player, target)
|
|
||||||
local amount = tonumber(amount)
|
|
||||||
local player = tonumber(player)
|
|
||||||
local target = tonumber(target)
|
|
||||||
if player == target then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "You can't give money to yourself."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
elseif GetPlayerPing(target) == 0 then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "That player does not exist."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
elseif amount <= 0 then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "You can't give that amount."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
elseif NDCore.Players[player].cash < amount then
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "You don't have enough money."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = cash - ? WHERE character_id = ?", {amount, NDCore.Players[player].id})
|
|
||||||
NDCore.Functions.UpdateMoney(player)
|
|
||||||
TriggerEvent("ND:moneyChange", player, "cash", amount, "remove")
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", "You gave " .. NDCore.Players[target].firstName .. " " .. NDCore.Players[target].lastName .. " $" .. amount .. "."}
|
|
||||||
})
|
|
||||||
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = cash + ? WHERE character_id = ?", {amount, NDCore.Players[target].id})
|
|
||||||
NDCore.Functions.UpdateMoney(target)
|
|
||||||
TriggerEvent("ND:moneyChange", target, "cash", amount, "add")
|
|
||||||
TriggerClientEvent("chat:addMessage", target, {
|
|
||||||
color = {0, 255, 0},
|
|
||||||
args = {"Success", " Received $" .. amount .. "."}
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Give money from a players wallet to a nearby player.
|
|
||||||
function NDCore.Functions.GiveCashToNearbyPlayer(player, amount)
|
|
||||||
local targetId = NDCore.Functions.GetNearbyPedToPlayer(player)
|
|
||||||
if targetId then
|
|
||||||
NDCore.Functions.GiveCash(amount, player, targetId)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
TriggerClientEvent("chat:addMessage", player, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
args = {"Error", "No players nearby."}
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- withdraws money from a players bank account to their wallet/cash.
|
|
||||||
function NDCore.Functions.WithdrawMoney(amount, player)
|
|
||||||
local amount = tonumber(amount)
|
|
||||||
local player = tonumber(player)
|
|
||||||
if amount <= 0 then return false end
|
|
||||||
if NDCore.Players[player].bank < amount then return false end
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = bank - ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = cash + ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
NDCore.Functions.UpdateMoney(player)
|
|
||||||
TriggerEvent("ND:moneyChange", player, "bank", amount, "remove", "Withdraw")
|
|
||||||
TriggerEvent("ND:moneyChange", player, "cash", amount, "add", "Withdraw")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- deposits money from a players wallet/cash to their bank account.
|
|
||||||
function NDCore.Functions.DepositMoney(amount, player)
|
|
||||||
local amount = tonumber(amount)
|
|
||||||
local player = tonumber(player)
|
|
||||||
if amount <= 0 then return false end
|
|
||||||
if NDCore.Players[player].cash < amount then return false end
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = cash - ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = bank + ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
NDCore.Functions.UpdateMoney(player)
|
|
||||||
TriggerEvent("ND:moneyChange", player, "cash", amount, "remove", "Deposit")
|
|
||||||
TriggerEvent("ND:moneyChange", player, "bank", amount, "add", "Deposit")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Deducts money from the player, "bank" or "cash" needs to be specified.
|
|
||||||
function NDCore.Functions.DeductMoney(amount, player, from, description)
|
|
||||||
local amount = tonumber(amount)
|
|
||||||
local player = tonumber(player)
|
|
||||||
if from == "bank" then
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = bank - ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
elseif from == "cash" then
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = cash - ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
end
|
|
||||||
NDCore.Functions.UpdateMoney(player)
|
|
||||||
TriggerEvent("ND:moneyChange", player, from, amount, "remove", description)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Adds money from the player, "bank" or "cash" needs to be specified.
|
|
||||||
function NDCore.Functions.AddMoney(amount, player, to, description)
|
|
||||||
local amount = tonumber(amount)
|
|
||||||
local player = tonumber(player)
|
|
||||||
if to == "bank" then
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = bank + ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
elseif to == "cash" then
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = cash + ? WHERE character_id = ? LIMIT 1", {amount, NDCore.Players[player].id})
|
|
||||||
end
|
|
||||||
NDCore.Functions.UpdateMoney(player)
|
|
||||||
TriggerEvent("ND:moneyChange", player, to, amount, "add", description)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Adds the players character to the NDCore.Players table, this table consists of every players selected character.
|
|
||||||
function NDCore.Functions.SetActiveCharacter(player, characterId)
|
|
||||||
if NDCore.Players[player] then
|
|
||||||
TriggerEvent("ND:characterUnloaded", player, NDCore.Players[player])
|
|
||||||
end
|
|
||||||
local result = MySQL.query.await("SELECT * FROM characters WHERE character_id = ? LIMIT 1", {characterId})
|
|
||||||
if result then
|
|
||||||
local i = result[1]
|
|
||||||
NDCore.Players[player] = {
|
|
||||||
source = player,
|
|
||||||
id = characterId,
|
|
||||||
firstName = i.first_name,
|
|
||||||
lastName = i.last_name,
|
|
||||||
dob = i.dob,
|
|
||||||
gender = i.gender,
|
|
||||||
cash = i.cash,
|
|
||||||
bank = i.bank,
|
|
||||||
phoneNumber = i.phone_number,
|
|
||||||
lastLocation = json.decode(i.last_location),
|
|
||||||
inventory = json.decode(i.inventory),
|
|
||||||
discordInfo = NDCore.PlayersDiscordInfo[player],
|
|
||||||
data = json.decode(i.data),
|
|
||||||
job = i.job
|
|
||||||
}
|
|
||||||
end
|
|
||||||
NDCore.Functions.RefreshCommands(player)
|
|
||||||
TriggerEvent("ND:characterLoaded", NDCore.Players[player])
|
|
||||||
TriggerClientEvent("ND:setCharacter", player, NDCore.Players[player])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This returns all the characters the player has.
|
|
||||||
function NDCore.Functions.GetPlayerCharacters(player)
|
|
||||||
local characters = {}
|
|
||||||
local result = MySQL.query.await("SELECT * FROM characters WHERE license = ?", {NDCore.Functions.GetPlayerIdentifierFromType("license", player)})
|
|
||||||
for i = 1, #result do
|
|
||||||
local temp = result[i]
|
|
||||||
characters[temp.character_id] = {
|
|
||||||
id = temp.character_id,
|
|
||||||
firstName = temp.first_name,
|
|
||||||
lastName = temp.last_name,
|
|
||||||
dob = temp.dob,
|
|
||||||
gender = temp.gender,
|
|
||||||
cash = temp.cash,
|
|
||||||
bank = temp.bank,
|
|
||||||
phoneNumber = temp.phone_number,
|
|
||||||
lastLocation = json.decode(temp.last_location),
|
|
||||||
inventory = json.decode(temp.inventory),
|
|
||||||
discordInfo = NDCore.PlayersDiscordInfo[player],
|
|
||||||
data = json.decode(temp.data),
|
|
||||||
job = temp.job
|
|
||||||
}
|
|
||||||
end
|
|
||||||
return characters
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Creates a new character for the player and returns all their characters to the client.
|
|
||||||
function NDCore.Functions.CreateCharacter(player, firstName, lastName, dob, gender, cb)
|
|
||||||
local characterId = false
|
|
||||||
local license = NDCore.Functions.GetPlayerIdentifierFromType("license", player)
|
|
||||||
local result = MySQL.query.await("SELECT character_id FROM characters WHERE license = ?", {license})
|
|
||||||
if result and config.characterLimit > #result then
|
|
||||||
characterId = MySQL.insert.await("INSERT INTO characters (license, first_name, last_name, dob, gender, cash, bank, data) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", {license, firstName, lastName, dob, gender, config.startingCash, config.startingBank, json.encode({groups={}})})
|
|
||||||
if cb then cb(characterId) end
|
|
||||||
TriggerClientEvent("ND:returnCharacters", player, NDCore.Functions.GetPlayerCharacters(player))
|
|
||||||
end
|
|
||||||
return characterId
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Update/edit a character info by character id.
|
|
||||||
function NDCore.Functions.UpdateCharacter(characterId, firstName, lastName, dob, gender)
|
|
||||||
local result = MySQL.query.await("UPDATE characters SET first_name = ?, last_name = ?, dob = ?, gender = ? WHERE character_id = ? LIMIT 1", {firstName, lastName, dob, gender, characterId})
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Delete a character by character id.
|
|
||||||
function NDCore.Functions.DeleteCharacter(characterId)
|
|
||||||
local result = MySQL.query.await("DELETE FROM characters WHERE character_id = ? LIMIT 1", {characterId})
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Updates the player's data
|
|
||||||
function NDCore.Functions.SetPlayerData(characterId, key, value, description)
|
|
||||||
if not key then return end
|
|
||||||
|
|
||||||
local player = nil
|
|
||||||
for id, character in pairs(NDCore.Players) do
|
|
||||||
if character.id == characterId then
|
|
||||||
player = id
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if key == "cash" then
|
|
||||||
if player then
|
|
||||||
NDCore.Players[player][key] = value
|
|
||||||
TriggerEvent("ND:moneyChange", player, "cash", tonumber(value), "set", description)
|
|
||||||
end
|
|
||||||
MySQL.query.await("UPDATE characters SET cash = ? WHERE character_id = ?", {tonumber(value), characterId})
|
|
||||||
elseif key == "bank" then
|
|
||||||
if player then
|
|
||||||
NDCore.Players[player][key] = value
|
|
||||||
TriggerEvent("ND:moneyChange", player, "bank", tonumber(value), "set", description)
|
|
||||||
end
|
|
||||||
MySQL.query.await("UPDATE characters SET bank = ? WHERE character_id = ?", {tonumber(value), characterId})
|
|
||||||
elseif key == "job" then
|
|
||||||
if player then
|
|
||||||
NDCore.Players[player].job = value
|
|
||||||
end
|
|
||||||
MySQL.query.await("UPDATE characters SET job = ? WHERE character_id = ?", {value, characterId})
|
|
||||||
else
|
|
||||||
if player then
|
|
||||||
NDCore.Players[player].data[key] = value
|
|
||||||
MySQL.query.await("UPDATE characters SET `data` = ? WHERE character_id = ?", {json.encode(NDCore.Players[player].data), characterId})
|
|
||||||
else
|
|
||||||
local result = MySQL.query.await("SELECT `data` FROM characters WHERE character_id = ?", {characterId})
|
|
||||||
if not result or not result[1] then return end
|
|
||||||
|
|
||||||
local data = json.decode(result[1].data)
|
|
||||||
data[key] = value
|
|
||||||
MySQL.query.await("UPDATE characters SET `data` = ? WHERE character_id = ?", {json.encode(data), characterId})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not player then return end
|
|
||||||
TriggerClientEvent("ND:updateCharacter", player, NDCore.Players[player])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get a character by the character id.
|
|
||||||
function NDCore.Functions.GetPlayerByCharacterId(id)
|
|
||||||
for _, character in pairs(NDCore.Players) do
|
|
||||||
if character.id == id then
|
|
||||||
return character
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Generate a random string with letters and numbers.
|
|
||||||
function randomString(length)
|
|
||||||
local number = {}
|
|
||||||
for i = 1, length do
|
|
||||||
number[i] = math.random(0, 1) == 1 and string.char(math.random(65, 90)) or math.random(0, 9)
|
|
||||||
end
|
|
||||||
return table.concat(number)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Give a player a license.
|
|
||||||
function NDCore.Functions.CreatePlayerLicense(characterId, licenseType, expire)
|
|
||||||
local expireIn = tonumber(expire)
|
|
||||||
if not expireIn then
|
|
||||||
expireIn = 2592000
|
|
||||||
end
|
|
||||||
|
|
||||||
local time = os.time()
|
|
||||||
local license = {
|
|
||||||
type = licenseType,
|
|
||||||
status = "valid",
|
|
||||||
issued = time,
|
|
||||||
expires = time+expireIn,
|
|
||||||
identifier = randomString(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
local character = NDCore.Functions.GetPlayerByCharacterId(characterId)
|
|
||||||
if character then
|
|
||||||
local data = character.data
|
|
||||||
if not data.licences then
|
|
||||||
data.licences = {}
|
|
||||||
end
|
|
||||||
character.data.licences[#character.data.licences+1] = license
|
|
||||||
NDCore.Functions.SetPlayerData(character.id, "licences", character.data.licences)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = MySQL.query.await("SELECT data FROM characters WHERE character_id = ?", {characterId})
|
|
||||||
if result and result[1] then
|
|
||||||
local data = result[1].data
|
|
||||||
if not data.licences then
|
|
||||||
data.licences = {}
|
|
||||||
end
|
|
||||||
data.licences[#data.licences+1] = license
|
|
||||||
NDCore.Functions.SetPlayerData(character.id, "licences", data.licences)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- find a players license by it's identifier.
|
|
||||||
function NDCore.Functions.FindLicenseByIdentifier(licences, identifier)
|
|
||||||
for key, license in pairs(licences) do
|
|
||||||
if license.identifier == identifier then
|
|
||||||
return license
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Edit a license by the license identifier.
|
|
||||||
function NDCore.Functions.EditPlayerLicense(characterId, identifier, newData)
|
|
||||||
local licences = {}
|
|
||||||
local character = NDCore.Functions.GetPlayerByCharacterId(characterId)
|
|
||||||
if character then
|
|
||||||
licences = character.data.licences
|
|
||||||
else
|
|
||||||
local result = MySQL.query.await("SELECT data FROM characters WHERE character_id = ?", {characterId})
|
|
||||||
if result and result[1] then
|
|
||||||
local data = result[1].data
|
|
||||||
if not data.licences then
|
|
||||||
data.licences = {}
|
|
||||||
end
|
|
||||||
licences = data.licences
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local license = NDCore.Functions.FindLicenseByIdentifier(licences, identifier)
|
|
||||||
for k, v in pairs(newData) do
|
|
||||||
license[k] = v
|
|
||||||
end
|
|
||||||
NDCore.Functions.SetPlayerData(characterId, "licences", licences)
|
|
||||||
return licences
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set the players job and job rank.
|
|
||||||
function NDCore.Functions.SetPlayerJob(characterId, job, rank)
|
|
||||||
if not job then return end
|
|
||||||
|
|
||||||
local jobRank = tonumber(rank)
|
|
||||||
if not jobRank then
|
|
||||||
jobRank = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = MySQL.query.await("SELECT job FROM characters WHERE character_id = ?", {characterId})
|
|
||||||
if result and result[1] then
|
|
||||||
local character = NDCore.Functions.GetPlayerByCharacterId(characterId)
|
|
||||||
if character then
|
|
||||||
local oldRank = 1
|
|
||||||
if character.data.groups and character.data.groups[character.job] then
|
|
||||||
oldRank = character.data.groups[character.job].rank
|
|
||||||
end
|
|
||||||
TriggerEvent("ND:jobChanged", character.source, {name = job, rank = jobRank}, {name = character.job, rank = oldRank})
|
|
||||||
TriggerClientEvent("ND:jobChanged", character.source, {name = job, rank = jobRank}, {name = character.job, rank = oldRank})
|
|
||||||
end
|
|
||||||
NDCore.Functions.RemovePlayerFromGroup(characterId, result[1].job)
|
|
||||||
end
|
|
||||||
|
|
||||||
NDCore.Functions.SetPlayerData(characterId, "job", job)
|
|
||||||
NDCore.Functions.SetPlayerToGroup(characterId, job, jobRank)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set a player to a group.
|
|
||||||
function NDCore.Functions.SetPlayerToGroup(characterId, group, rank)
|
|
||||||
local groupRank = tonumber(rank)
|
|
||||||
if not groupRank then
|
|
||||||
groupRank = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local group = group:lower()
|
|
||||||
for groupName, groupRanks in pairs(config.groups) do
|
|
||||||
if groupName:lower() == group then
|
|
||||||
group = groupName
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local character = NDCore.Functions.GetPlayerByCharacterId(characterId)
|
|
||||||
if character then
|
|
||||||
local data = character.data
|
|
||||||
if not data.groups then
|
|
||||||
data.groups = {}
|
|
||||||
end
|
|
||||||
local rankName = tostring(groupRank)
|
|
||||||
if config.groups[group] and config.groups[group][groupRank] then
|
|
||||||
rankName = config.groups[group][groupRank]
|
|
||||||
end
|
|
||||||
data.groups[group] = {
|
|
||||||
rank = groupRank,
|
|
||||||
rankName = rankName
|
|
||||||
}
|
|
||||||
NDCore.Functions.SetPlayerData(characterId, "groups", data.groups)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = MySQL.query.await("SELECT data FROM characters WHERE character_id = ?", {characterId})
|
|
||||||
if not result or not result[1] then return end
|
|
||||||
local data = json.decode(result[1].data)
|
|
||||||
if not data then
|
|
||||||
data = {}
|
|
||||||
end
|
|
||||||
if not data.groups then
|
|
||||||
data.groups = {}
|
|
||||||
end
|
|
||||||
local rankName = tostring(groupRank)
|
|
||||||
if config.groups[group] and config.groups[group][groupRank] then
|
|
||||||
rankName = config.groups[group][groupRank]
|
|
||||||
end
|
|
||||||
data.groups[group] = {
|
|
||||||
rank = groupRank,
|
|
||||||
rankName = rankName
|
|
||||||
}
|
|
||||||
NDCore.Functions.SetPlayerData(characterId, "groups", data.groups)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Remove a player from a group.
|
|
||||||
function NDCore.Functions.RemovePlayerFromGroup(characterId, group)
|
|
||||||
if not group then return end
|
|
||||||
local group = group:lower()
|
|
||||||
for groupName, groupRanks in pairs(config.groups) do
|
|
||||||
if groupName:lower() == group then
|
|
||||||
group = groupName
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local character = NDCore.Functions.GetPlayerByCharacterId(characterId)
|
|
||||||
if character then
|
|
||||||
local data = character.data
|
|
||||||
if not data.groups then
|
|
||||||
data.groups = {}
|
|
||||||
end
|
|
||||||
data.groups[group] = nil
|
|
||||||
NDCore.Functions.SetPlayerData(characterId, "groups", data.groups)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = MySQL.query.await("SELECT data FROM characters WHERE character_id = ?", {characterId})
|
|
||||||
if result and result[1] then
|
|
||||||
local data = result[1].data
|
|
||||||
if not data.groups then
|
|
||||||
data.groups = {}
|
|
||||||
end
|
|
||||||
data.groups[group] = nil
|
|
||||||
NDCore.Functions.SetPlayerData(characterId, "groups", data.groups)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Update the characters last location into the database.
|
|
||||||
function NDCore.Functions.UpdateLastLocation(characterId, location)
|
|
||||||
local result = MySQL.query.await("UPDATE characters SET last_location = ? WHERE character_id = ? LIMIT 1", {json.encode(location), characterId})
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.Functions.AddCommand(name, help, callback, argsrequired, arguments)
|
|
||||||
local commandName = name:lower()
|
|
||||||
if NDCore.Commands[commandName] then print("/" .. commandName .. " has already been registered.") return end
|
|
||||||
|
|
||||||
local arguments = arguments or {}
|
|
||||||
|
|
||||||
RegisterCommand(commandName, function(source, args, rawCommand)
|
|
||||||
if argsrequired and #args < #arguments then
|
|
||||||
return TriggerClientEvent("chat:addMessage", source, {
|
|
||||||
color = {255, 0, 0},
|
|
||||||
multiline = true,
|
|
||||||
args = {"Error", "all arguments required."}
|
|
||||||
})
|
|
||||||
end
|
|
||||||
local message = callback(source, args, rawCommand)
|
|
||||||
if not message then return end
|
|
||||||
TriggerClientEvent("chat:addMessage", source, message)
|
|
||||||
end, false)
|
|
||||||
|
|
||||||
NDCore.Commands[commandName] = {
|
|
||||||
name = commandName,
|
|
||||||
help = help,
|
|
||||||
callback = callback,
|
|
||||||
argsrequired = argsrequired,
|
|
||||||
arguments = arguments
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.Functions.RefreshCommands(source)
|
|
||||||
local suggestions = {}
|
|
||||||
for command, info in pairs(NDCore.Commands) do
|
|
||||||
suggestions[#suggestions + 1] = {
|
|
||||||
name = "/" .. command,
|
|
||||||
help = info.help,
|
|
||||||
params = info.arguments
|
|
||||||
}
|
|
||||||
end
|
|
||||||
TriggerClientEvent("chat:addSuggestions", source, suggestions)
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.Functions.IsPlayerAdmin(src)
|
|
||||||
local discordInfo = NDCore.PlayersDiscordInfo[src]
|
|
||||||
if not discordInfo or not discordInfo.roles then return end
|
|
||||||
for _, adminRole in pairs(config.adminRoles) do
|
|
||||||
for _, role in pairs(discordInfo.roles) do
|
|
||||||
if role == adminRole then return true end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.Functions.VersionChecker(expectedResourceName, resourceName, downloadLink, rawGithubLink)
|
|
||||||
if expectedResourceName ~= resourceName then
|
|
||||||
print(("^4%s ^1WARNING^0"):format(expectedResourceName))
|
|
||||||
print(("Change the resource name to ^4%s ^0or else it won't work properly!"):format(expectedResourceName))
|
|
||||||
StopResource(resourceName)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
PerformHttpRequest(rawGithubLink, function(errorCode, resultData, resultHeaders)
|
|
||||||
local i, j = tostring(resultData):find("version")
|
|
||||||
if not i or not j then return end
|
|
||||||
local resultData = tostring(resultData):sub(i, j + 12)
|
|
||||||
local resultData = resultData:gsub("version \"", "")
|
|
||||||
local i, j = resultData:find("\"")
|
|
||||||
local resultData = resultData:sub(1, i - 1)
|
|
||||||
local githubVersion = resultData:gsub("%.", "")
|
|
||||||
local fileVersion = GetResourceMetadata(expectedResourceName, "version", 0):gsub("%.", "")
|
|
||||||
|
|
||||||
if not githubVersion and not fileVersion then
|
|
||||||
print(("^4%s ^1WARNING^0"):format(expectedResourceName))
|
|
||||||
print(("You may not have the latest version of ^4%s^0. A newer, improved version may be present at ^5%s^0"):format(expectedResourceName, downloadLink))
|
|
||||||
elseif githubVersion > fileVersion then
|
|
||||||
local oldVersion = ("%s.%s.%s"):format(fileVersion:sub(1, 1), fileVersion:sub(2, 2), fileVersion:sub(3, 3))
|
|
||||||
local newVersion = ("%s.%s.%s"):format(githubVersion:sub(1, 1), githubVersion:sub(2, 2), githubVersion:sub(3, 3))
|
|
||||||
print(("^4%s ^1WARNING^0"):format(expectedResourceName))
|
|
||||||
print(("^4%s ^0is outdated. Please update it from ^5%s ^0| Current Version: ^1%s ^0| New Version: ^2%s ^0|"):format(expectedResourceName, downloadLink, oldVersion, newVersion))
|
|
||||||
elseif githubVersion < fileVersion then
|
|
||||||
local oldVersion = ("%s.%s.%s"):format(fileVersion:sub(1, 1), fileVersion:sub(2, 2), fileVersion:sub(3, 3))
|
|
||||||
local newVersion = ("%s.%s.%s"):format(githubVersion:sub(1, 1), githubVersion:sub(2, 2), githubVersion:sub(3, 3))
|
|
||||||
print(("^4%s ^1WARNING^0"):format(expectedResourceName))
|
|
||||||
print(("^4%s ^0version number is higher than expected | Current Version: ^3%s ^0| Expected Version: ^2%s ^0|"):format(expectedResourceName, oldVersion, newVersion))
|
|
||||||
else
|
|
||||||
local newVersion = ("%s.%s.%s"):format(githubVersion:sub(1, 1), githubVersion:sub(2, 2), githubVersion:sub(3, 3))
|
|
||||||
print(("^4%s ^0is up to date | Current Version: ^2%s ^0|"):format(expectedResourceName, newVersion))
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
NDCore.Functions.VersionChecker("ND_Core", GetCurrentResourceName(), "https://github.com/ND-Framework/ND_Core", "https://raw.githubusercontent.com/ND-Framework/ND_Core/main/fxmanifest.lua")
|
|
||||||
|
|
||||||
|
|
||||||
-- Callbacks are licensed under LGPL v3.0
|
|
||||||
-- <https://github.com/overextended/ox_lib>
|
|
||||||
NDCore.callback = {}
|
|
||||||
local events = {}
|
|
||||||
|
|
||||||
RegisterNetEvent("ND:callbacks", function(key, ...)
|
|
||||||
local cb = events[key]
|
|
||||||
return cb and cb(...)
|
|
||||||
end)
|
|
||||||
|
|
||||||
function triggerCallback(_, name, playerId, cb, ...)
|
|
||||||
local key = ("%s:%s:%s"):format(name, math.random(0, 100000), playerId)
|
|
||||||
TriggerClientEvent(("ND:%s_cb"):format(name), playerId, key, ...)
|
|
||||||
|
|
||||||
local promise = not cb and promise.new()
|
|
||||||
|
|
||||||
events[key] = function(response, ...)
|
|
||||||
response = { response, ... }
|
|
||||||
events[key] = nil
|
|
||||||
|
|
||||||
if promise then
|
|
||||||
return promise:resolve(response)
|
|
||||||
end
|
|
||||||
|
|
||||||
if cb then
|
|
||||||
cb(table.unpack(response))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if promise then
|
|
||||||
return table.unpack(Citizen.Await(promise))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
setmetatable(NDCore.callback, {
|
|
||||||
__call = triggerCallback
|
|
||||||
})
|
|
||||||
|
|
||||||
function NDCore.callback.await(name, playerId, ...)
|
|
||||||
return triggerCallback(nil, name, playerId, false, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function NDCore.callback.register(name, callback)
|
|
||||||
RegisterNetEvent(("ND:%s_cb"):format(name), function(key, ...)
|
|
||||||
local src = source
|
|
||||||
TriggerClientEvent("ND:callbacks", src, key, callback(src, ...))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
@@ -1,21 +1,14 @@
|
|||||||
-- For support join my discord: https://discord.gg/Z9Mxu72zZ6
|
ActivePlayers = {}
|
||||||
|
|
||||||
NDCore = {}
|
function NDCore.getPlayer(src)
|
||||||
NDCore.Players = {}
|
return ActivePlayers[src]
|
||||||
NDCore.Functions = {}
|
|
||||||
NDCore.Commands = {}
|
|
||||||
NDCore.PlayersDiscordInfo = {}
|
|
||||||
NDCore.Config = config
|
|
||||||
|
|
||||||
function GetCoreObject()
|
|
||||||
return NDCore
|
|
||||||
end
|
end
|
||||||
|
|
||||||
isResourceStarted("ox_inventory", function(started)
|
AddEventHandler("playerDropped", function()
|
||||||
if not started then return end
|
local src = source
|
||||||
SetConvarReplicated("inventory:framework", "nd")
|
local char = ActivePlayers[src]
|
||||||
|
if not char then return end
|
||||||
|
char:unload()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
for _, roleid in pairs(config.adminRoles) do
|
SetConvarServerInfo("ND_Core", GetResourceMetadata(GetCurrentResourceName(), "version", 0) or "invalid")
|
||||||
ExecuteCommand("add_principal identifier.discord:" .. roleid .. " group.admin")
|
|
||||||
end
|
|
||||||
|
|||||||
192
server/player.lua
Normal file
192
server/player.lua
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
local function charDelete(self)
|
||||||
|
local result = MySQL.query.await("DELETE FROM nd_characters WHERE charid = ?", {self.id})
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charDeductMoney(self, account, amount, reason)
|
||||||
|
local amount = tonumber(amount)
|
||||||
|
if not amount or account ~= "bank" and account ~= "cash" then return end
|
||||||
|
self[account] -= amount
|
||||||
|
if self.source then
|
||||||
|
TriggerEvent("ND:moneyChange", self.source, account, amount, "remove", reason)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charAddMoney(self, account, amount, reason)
|
||||||
|
local amount = tonumber(amount)
|
||||||
|
if not amount or account ~= "bank" and account ~= "cash" then return end
|
||||||
|
self[account] += amount
|
||||||
|
if self.source then
|
||||||
|
TriggerEvent("ND:moneyChange", self.source, account, amount, "add", reason)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charDepositMoney(self, amount)
|
||||||
|
local amount = tonumber(amount)
|
||||||
|
if not amount or self.cash < amount or amount <= 0 then return end
|
||||||
|
return self:deductMoney("cash", amount, "Deposit") and self:AddMoney("bank", amount, "Deposit")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charWithdrawMoney(self, amount)
|
||||||
|
local amount = tonumber(amount)
|
||||||
|
if not amount or self.bank < amount or amount <= 0 then return end
|
||||||
|
return self:deductMoney("bank", amount, "Withdraw") and self:AddMoney("cash", amount, "Withdraw")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charSetMetadata(self, key, value)
|
||||||
|
self.metadata[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charUnload(self)
|
||||||
|
TriggerEvent("ND:characterUnloaded", self.source, self)
|
||||||
|
local ped = GetPlayerPed(self.source)
|
||||||
|
self:setMetadata("location", GetEntityCoords(ped))
|
||||||
|
self:save()
|
||||||
|
ActivePlayers[self.source] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charSave(self)
|
||||||
|
MySQL.update.await("UPDATE nd_characters SET name = ?, firstname = ?, lastname = ?, dob = ?, gender = ?, cash = ?, bank = ?, metadata = ?, inventory = ? WHERE charid = ?", {
|
||||||
|
self.name,
|
||||||
|
self.firstname,
|
||||||
|
self.lastname,
|
||||||
|
self.dob,
|
||||||
|
self.gender,
|
||||||
|
self.cash,
|
||||||
|
self.bank,
|
||||||
|
json.encode(self.metadata),
|
||||||
|
json.encode(self.inventory),
|
||||||
|
self.id,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function charCreateLicense(self, licenseType, expire)
|
||||||
|
local expireIn = tonumber(expire) or 2592000
|
||||||
|
local time = os.time()
|
||||||
|
local licenses = self.metadata.licenses
|
||||||
|
local identifier = {}
|
||||||
|
|
||||||
|
for i=1, 16 do
|
||||||
|
identifier[i] = math.random(0, 1) == 1 and string.char(math.random(65, 90)) or math.random(0, 9)
|
||||||
|
end
|
||||||
|
|
||||||
|
local license = {
|
||||||
|
type = licenseType,
|
||||||
|
status = "valid",
|
||||||
|
issued = time,
|
||||||
|
expires = time+expireIn,
|
||||||
|
identifier = table.concat(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
if licenses then
|
||||||
|
self.metadata.licenses[#licenses+1] = license
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.metadata.licenses = {license}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function initPlayerTable(playerTable)
|
||||||
|
playerTable.delete = charDelete,
|
||||||
|
playerTable.deductMoney = charDeductMoney,
|
||||||
|
playerTable.addMoney = charAddMoney
|
||||||
|
playerTable.depositMoney = charDepositMoney,
|
||||||
|
playerTable.withdrawMoney = charWithdrawMoney,
|
||||||
|
playerTable.setMetadata = charSetMetadata,
|
||||||
|
playerTable.save = charSave,
|
||||||
|
playerTable.unload = charUnload,
|
||||||
|
playerTable.createLicense = charCreateLicense
|
||||||
|
return playerTable
|
||||||
|
end
|
||||||
|
|
||||||
|
function NDCore.newCharacter(src, info)
|
||||||
|
local license = GetPlayerIdentifierByType(src, "license")
|
||||||
|
if not license then return end
|
||||||
|
|
||||||
|
local charInfo = initPlayerTable({
|
||||||
|
source = src,
|
||||||
|
name = GetPlayerName(src) or "",
|
||||||
|
firstname = info.firstname or "",
|
||||||
|
lastname = info.lastname or "",
|
||||||
|
dob = info.dob or "",
|
||||||
|
gender = info.gender or "",
|
||||||
|
cash = info.cash or 0,
|
||||||
|
bank = info.bank or 0,
|
||||||
|
license = license,
|
||||||
|
metadata = info.metadata or {},
|
||||||
|
inventory = info.inventory or {},
|
||||||
|
})
|
||||||
|
|
||||||
|
charInfo.id = MySQL.insert.await("INSERT INTO nd_characters (license, name, firstname, lastname, dob, gender, cash, bank, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", {
|
||||||
|
license,
|
||||||
|
charInfo.name,
|
||||||
|
charInfo.firstname,
|
||||||
|
charInfo.lastname,
|
||||||
|
charInfo.dob,
|
||||||
|
charInfo.gender,
|
||||||
|
charInfo.cash,
|
||||||
|
charInfo.bank,
|
||||||
|
charInfo.metadata
|
||||||
|
)
|
||||||
|
|
||||||
|
return charInfo
|
||||||
|
end
|
||||||
|
|
||||||
|
function NDCore.fetchCharacter(id)
|
||||||
|
local result = MySQL.query.await("SELECT * FROM nd_characters WHERE charid = ?", {id})
|
||||||
|
if not result then return end
|
||||||
|
|
||||||
|
local info = result[1]
|
||||||
|
return initPlayerTable({
|
||||||
|
id = id,
|
||||||
|
name = info.name,
|
||||||
|
firstname = info.firstname,
|
||||||
|
lastname = info.lastname,
|
||||||
|
dob = info.dob,
|
||||||
|
gender = info.gender,
|
||||||
|
cash = info.cash,
|
||||||
|
bank = info.bank,
|
||||||
|
license = info.license,
|
||||||
|
metadata = json.decode(info.metadata),
|
||||||
|
inventory = json.decode(i.inventory)
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function NDCore.getPlayerCharacters(src)
|
||||||
|
local characters = {}
|
||||||
|
local result = MySQL.query.await("SELECT * FROM nd_characters WHERE license = ?", {GetPlayerIdentifierByType(src, "license")})
|
||||||
|
local amount = #result
|
||||||
|
|
||||||
|
for i=1, amount do
|
||||||
|
local info = result[i]
|
||||||
|
characters[info.charid] = initPlayerTable({
|
||||||
|
id = info.charid,
|
||||||
|
name = info.name,
|
||||||
|
firstname = info.firstname,
|
||||||
|
lastname = info.lastname,
|
||||||
|
dob = info.dob,
|
||||||
|
gender = info.gender,
|
||||||
|
cash = info.cash,
|
||||||
|
bank = info.bank,
|
||||||
|
license = info.license,
|
||||||
|
metadata = json.decode(info.metadata),
|
||||||
|
inventory = json.decode(info.inventory),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
return characters
|
||||||
|
end
|
||||||
|
|
||||||
|
function NDCore.setActiveCharacter(src, id)
|
||||||
|
local char = ActivePlayers[src]
|
||||||
|
if char then char:unload() end
|
||||||
|
|
||||||
|
local character = NDCore.fetchCharacter(id)
|
||||||
|
character.source = src,
|
||||||
|
character.name = GetPlayerName(src)
|
||||||
|
ActivePlayers[src] = character
|
||||||
|
|
||||||
|
TriggerEvent("ND:characterLoaded", character)
|
||||||
|
TriggerClientEvent("ND:characterLoaded", src, character)
|
||||||
|
return ActivePlayers[src]
|
||||||
|
end
|
||||||
@@ -1 +0,0 @@
|
|||||||
NDCore = exports["ND_Core"]:GetCoreObject()
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
local startedResources = {}
|
|
||||||
local callbacks = {}
|
|
||||||
|
|
||||||
AddEventHandler("onResourceStart", function(resourceName)
|
|
||||||
startedResources[resourceName] = true
|
|
||||||
local callback = callbacks[resourceName]
|
|
||||||
if not callback then return end
|
|
||||||
callback(true)
|
|
||||||
end)
|
|
||||||
|
|
||||||
AddEventHandler("onResourceStop", function(resourceName)
|
|
||||||
startedResources[resourceName] = nil
|
|
||||||
local callback = callbacks[resourceName]
|
|
||||||
if not callback then return end
|
|
||||||
callback(false)
|
|
||||||
end)
|
|
||||||
|
|
||||||
function isResourceStarted(resourceName, cb)
|
|
||||||
local started = GetResourceState(resourceName) == "started"
|
|
||||||
startedResources[resourceName] = started
|
|
||||||
|
|
||||||
if cb then
|
|
||||||
callbacks[resourceName] = cb
|
|
||||||
cb(started)
|
|
||||||
end
|
|
||||||
|
|
||||||
return started
|
|
||||||
end
|
|
||||||
|
|
||||||
exports("isResourceStarted", isResourceStarted)
|
|
||||||
Reference in New Issue
Block a user