Skip to content

Commit 713d9bc

Browse files
authored
Merge pull request #1702 from esx-framework/ssn
feat(es_extended): add SSN
2 parents 0805ac0 + ffd5946 commit 713d9bc

File tree

5 files changed

+69
-7
lines changed

5 files changed

+69
-7
lines changed

[SQL]/legacy.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ CREATE TABLE `society_moneywash` (
385385

386386
CREATE TABLE `users` (
387387
`identifier` varchar(60) NOT NULL,
388+
`ssn` VARCHAR(11) NOT NULL,
388389
`accounts` longtext DEFAULT NULL,
389390
`group` varchar(50) DEFAULT 'user',
390391
`inventory` longtext DEFAULT NULL,
@@ -847,6 +848,9 @@ ALTER TABLE `users`
847848
ADD PRIMARY KEY (`identifier`),
848849
ADD UNIQUE KEY `id` (`id`);
849850

851+
ALTER TABLE `users`
852+
ADD UNIQUE KEY `unique_ssn` (`ssn`);
853+
850854
--
851855
-- Indexes for table `user_licenses`
852856
--

[core]/es_extended/es_extended.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ USE `es_extended`;
1010

1111
CREATE TABLE `users` (
1212
`identifier` VARCHAR(60) NOT NULL,
13+
`ssn` VARCHAR(11) NOT NULL,
1314
`accounts` LONGTEXT NULL DEFAULT NULL,
1415
`group` VARCHAR(50) NULL DEFAULT 'user',
1516
`inventory` LONGTEXT NULL DEFAULT NULL,
@@ -19,7 +20,8 @@ CREATE TABLE `users` (
1920
`metadata` LONGTEXT NULL DEFAULT NULL,
2021
`position` longtext NULL DEFAULT NULL,
2122

22-
PRIMARY KEY (`identifier`)
23+
PRIMARY KEY (`identifier`),
24+
UNIQUE KEY `unique_ssn` (`ssn`)
2325
) ENGINE=InnoDB;
2426

2527
CREATE TABLE `items` (

[core]/es_extended/server/classes/player.lua

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
---@field getWeaponTint fun(weaponName: string): number # Get weapon tint.
8787
--- Player State Functions
8888
---@field getIdentifier fun(): string # Get player's unique identifier.
89+
---@field getSSN fun(): string # Get player's social security number.
8990
---@field getSource fun(): number # Get player source/server ID.
9091
---@field getPlayerId fun(): number # Alias for getSource.
9192
---@field getName fun(): string # Get player's name.
@@ -135,6 +136,7 @@
135136

136137
---@param playerId number
137138
---@param identifier string
139+
---@param ssn string
138140
---@param group string
139141
---@param accounts ESXAccount[]
140142
---@param inventory table
@@ -145,14 +147,15 @@
145147
---@param coords vector4|{x: number, y: number, z: number, heading: number}
146148
---@param metadata table
147149
---@return xPlayer
148-
function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, weight, job, loadout, name, coords, metadata)
150+
function CreateExtendedPlayer(playerId, identifier, ssn, group, accounts, inventory, weight, job, loadout, name, coords, metadata)
149151
---@diagnostic disable-next-line: missing-fields
150152
local self = {} ---@type xPlayer
151153

152154
self.accounts = accounts
153155
self.coords = coords
154156
self.group = group
155157
self.identifier = identifier
158+
self.ssn = ssn
156159
self.inventory = inventory
157160
self.job = job
158161
self.loadout = loadout
@@ -264,6 +267,10 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
264267
return self.identifier
265268
end
266269

270+
function self.getSSN()
271+
return self.ssn
272+
end
273+
267274
function self.setGroup(newGroup)
268275
local lastGroup = self.group
269276

[core]/es_extended/server/functions.lua

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,51 @@ function Core.IsPlayerAdmin(playerSrc)
817817
return xPlayer and Config.AdminGroups[xPlayer.getGroup()] or false
818818
end
819819

820+
-- Generates a unique 9-digit SSN in dashed format (XXX-XX-XXXX).
821+
---@return string
822+
function Core.generateSSN()
823+
local reservedSSNs = {
824+
["078-05-1120"] = true,
825+
["219-09-9999"] = true,
826+
["123-45-6789"] = true
827+
}
828+
829+
while true do
830+
-- Generate the first part (area number)
831+
local area = math.random(1, 899)
832+
833+
-- 666 is never assigned
834+
if area == 666 then
835+
goto continue
836+
end
837+
838+
-- Generate the second part (group number)
839+
local group = math.random(1, 99)
840+
841+
-- Generate the last part (serial number)
842+
local serial = math.random(1, 9999)
843+
844+
-- Skip reserved SSN range (987-65-4320..4329)
845+
if area == 987 and group == 65 and serial >= 4320 and serial <= 4329 then
846+
goto continue
847+
end
848+
849+
local candidate = string.format("%03d-%02d-%04d", area, group, serial)
850+
851+
if reservedSSNs[candidate] then
852+
goto continue
853+
end
854+
855+
local exists = MySQL.scalar.await("SELECT 1 FROM `users` WHERE `ssn` = ? LIMIT 1", { candidate })
856+
857+
if not exists then
858+
return candidate
859+
end
860+
861+
::continue::
862+
end
863+
end
864+
820865
---@param owner string
821866
---@param plate string
822867
---@param coords vector4

[core]/es_extended/server/main.lua

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ SetMapName("San Andreas")
22
SetGameType("ESX Legacy")
33

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

88
if Config.Multichar then
99
newPlayer = newPlayer .. ", `firstname` = ?, `lastname` = ?, `dateofbirth` = ?, `sex` = ?, `height` = ?"
@@ -31,8 +31,9 @@ local function createESXPlayer(identifier, playerId, data)
3131
print(("[^2INFO^0] Player ^5%s^0 Has been granted admin permissions via ^5Ace Perms^7."):format(playerId))
3232
defaultGroup = "admin"
3333
end
34-
35-
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 }
34+
local parameters = Config.Multichar and
35+
{ json.encode(accounts), identifier, Core.generateSSN(), defaultGroup, data.firstname, data.lastname, data.dateofbirth, data.sex, data.height }
36+
or { json.encode(accounts), identifier, Core.generateSSN(), defaultGroup }
3637

3738
if Config.StartingInventoryItems then
3839
table.insert(parameters, json.encode(Config.StartingInventoryItems))
@@ -216,6 +217,9 @@ function loadESXPlayer(identifier, playerId, isNew)
216217
}
217218
end
218219

220+
-- SSN
221+
userData.ssn = result.ssn
222+
219223
-- Job
220224
local job, grade = result.job, tostring(result.job_grade)
221225

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

310314
-- xPlayer Creation
311-
local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, GetPlayerName(playerId), userData.coords, userData.metadata)
315+
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)
312316

313317
GlobalState["playerCount"] = GlobalState["playerCount"] + 1
314318
ESX.Players[playerId] = xPlayer

0 commit comments

Comments
 (0)