Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions [SQL]/legacy.sql
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ CREATE TABLE `society_moneywash` (

CREATE TABLE `users` (
`identifier` varchar(60) NOT NULL,
`ssn` VARCHAR(11) NOT NULL,
`accounts` longtext DEFAULT NULL,
`group` varchar(50) DEFAULT 'user',
`inventory` longtext DEFAULT NULL,
Expand Down Expand Up @@ -847,6 +848,9 @@ ALTER TABLE `users`
ADD PRIMARY KEY (`identifier`),
ADD UNIQUE KEY `id` (`id`);

ALTER TABLE `users`
ADD UNIQUE KEY `unique_ssn` (`ssn`);

--
-- Indexes for table `user_licenses`
--
Expand Down
4 changes: 3 additions & 1 deletion [core]/es_extended/es_extended.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ USE `es_extended`;

CREATE TABLE `users` (
`identifier` VARCHAR(60) NOT NULL,
`ssn` VARCHAR(11) NOT NULL,
`accounts` LONGTEXT NULL DEFAULT NULL,
`group` VARCHAR(50) NULL DEFAULT 'user',
`inventory` LONGTEXT NULL DEFAULT NULL,
Expand All @@ -19,7 +20,8 @@ CREATE TABLE `users` (
`metadata` LONGTEXT NULL DEFAULT NULL,
`position` longtext NULL DEFAULT NULL,

PRIMARY KEY (`identifier`)
PRIMARY KEY (`identifier`),
UNIQUE KEY `unique_ssn` (`ssn`)
) ENGINE=InnoDB;

CREATE TABLE `items` (
Expand Down
9 changes: 8 additions & 1 deletion [core]/es_extended/server/classes/player.lua
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
---@field getWeaponTint fun(weaponName: string): number # Get weapon tint.
--- Player State Functions
---@field getIdentifier fun(): string # Get player's unique identifier.
---@field getSSN fun(): string # Get player's social security number.
---@field getSource fun(): number # Get player source/server ID.
---@field getPlayerId fun(): number # Alias for getSource.
---@field getName fun(): string # Get player's name.
Expand Down Expand Up @@ -135,6 +136,7 @@

---@param playerId number
---@param identifier string
---@param ssn string
---@param group string
---@param accounts ESXAccount[]
---@param inventory table
Expand All @@ -145,14 +147,15 @@
---@param coords vector4|{x: number, y: number, z: number, heading: number}
---@param metadata table
---@return xPlayer
function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, weight, job, loadout, name, coords, metadata)
function CreateExtendedPlayer(playerId, identifier, ssn, group, accounts, inventory, weight, job, loadout, name, coords, metadata)
---@diagnostic disable-next-line: missing-fields
local self = {} ---@type xPlayer

self.accounts = accounts
self.coords = coords
self.group = group
self.identifier = identifier
self.ssn = ssn
self.inventory = inventory
self.job = job
self.loadout = loadout
Expand Down Expand Up @@ -264,6 +267,10 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
return self.identifier
end

function self.getSSN()
return self.ssn
end

function self.setGroup(newGroup)
local lastGroup = self.group

Expand Down
45 changes: 45 additions & 0 deletions [core]/es_extended/server/functions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,51 @@ function Core.IsPlayerAdmin(playerSrc)
return xPlayer and Config.AdminGroups[xPlayer.getGroup()] or false
end

-- Generates a unique 9-digit SSN in dashed format (XXX-XX-XXXX).
---@return string
function Core.generateSSN()
local reservedSSNs = {
["078-05-1120"] = true,
["219-09-9999"] = true,
["123-45-6789"] = true
}

while true do
-- Generate the first part (area number)
local area = math.random(1, 899)

-- 666 is never assigned
if area == 666 then
goto continue
end

-- Generate the second part (group number)
local group = math.random(1, 99)

-- Generate the last part (serial number)
local serial = math.random(1, 9999)

-- Skip reserved SSN range (987-65-4320..4329)
if area == 987 and group == 65 and serial >= 4320 and serial <= 4329 then
goto continue
end

local candidate = string.format("%03d-%02d-%04d", area, group, serial)

if reservedSSNs[candidate] then
goto continue
end

local exists = MySQL.scalar.await("SELECT 1 FROM `users` WHERE `ssn` = ? LIMIT 1", { candidate })

if not exists then
return candidate
end

::continue::
end
end

---@param owner string
---@param plate string
---@param coords vector4
Expand Down
14 changes: 9 additions & 5 deletions [core]/es_extended/server/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ SetMapName("San Andreas")
SetGameType("ESX Legacy")

local oneSyncState = GetConvar("onesync", "off")
local newPlayer = "INSERT INTO `users` SET `accounts` = ?, `identifier` = ?, `group` = ?"
local loadPlayer = "SELECT `accounts`, `job`, `job_grade`, `group`, `position`, `inventory`, `skin`, `loadout`, `metadata`"
local newPlayer = "INSERT INTO `users` SET `accounts` = ?, `identifier` = ?, `ssn` = ?, `group` = ?"
local loadPlayer = "SELECT `accounts`, `ssn`, `job`, `job_grade`, `group`, `position`, `inventory`, `skin`, `loadout`, `metadata`"

if Config.Multichar then
newPlayer = newPlayer .. ", `firstname` = ?, `lastname` = ?, `dateofbirth` = ?, `sex` = ?, `height` = ?"
Expand Down Expand Up @@ -31,8 +31,9 @@ local function createESXPlayer(identifier, playerId, data)
print(("[^2INFO^0] Player ^5%s^0 Has been granted admin permissions via ^5Ace Perms^7."):format(playerId))
defaultGroup = "admin"
end

local parameters = Config.Multichar and { json.encode(accounts), identifier, defaultGroup, data.firstname, data.lastname, data.dateofbirth, data.sex, data.height } or { json.encode(accounts), identifier, defaultGroup }
local parameters = Config.Multichar and
{ json.encode(accounts), identifier, Core.generateSSN(), defaultGroup, data.firstname, data.lastname, data.dateofbirth, data.sex, data.height }
or { json.encode(accounts), identifier, Core.generateSSN(), defaultGroup }

if Config.StartingInventoryItems then
table.insert(parameters, json.encode(Config.StartingInventoryItems))
Expand Down Expand Up @@ -216,6 +217,9 @@ function loadESXPlayer(identifier, playerId, isNew)
}
end

-- SSN
userData.ssn = result.ssn

-- Job
local job, grade = result.job, tostring(result.job_grade)

Expand Down Expand Up @@ -308,7 +312,7 @@ function loadESXPlayer(identifier, playerId, isNew)
userData.metadata = (result.metadata and result.metadata ~= "") and json.decode(result.metadata) or {}

-- xPlayer Creation
local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, GetPlayerName(playerId), userData.coords, userData.metadata)
local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.ssn, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, GetPlayerName(playerId), userData.coords, userData.metadata)

GlobalState["playerCount"] = GlobalState["playerCount"] + 1
ESX.Players[playerId] = xPlayer
Expand Down