Files
2026-03-15 14:54:49 +03:00

305 lines
12 KiB
Lua

local meta = FindMetaTable("Player")
DarkRP.ServerDarkRPVars = DarkRP.ServerDarkRPVars or {}
DarkRP.ServerPrivateDarkRPVars = DarkRP.ServerPrivateDarkRPVars or {}
--[[---------------------------------------------------------------------------
Pooled networking strings
---------------------------------------------------------------------------]]
util.AddNetworkString("DarkRP_InitializeVars")
util.AddNetworkString("DarkRP_PlayerVar")
util.AddNetworkString("DarkRP_PlayerVarRemoval")
util.AddNetworkString("DarkRP_DarkRPVarDisconnect")
--[[---------------------------------------------------------------------------
Player vars
---------------------------------------------------------------------------]]
local warningsShown = {}
local function checkDarkRPVarRegistration(name)
local DarkRPVar = DarkRP.RegisteredDarkRPVars[name]
if DarkRPVar then return end
if warningsShown[name] then return end
warningsShown[name] = true
DarkRP.errorNoHalt(string.format([[Warning! DarkRPVar '%s' wasn't registered!
Please contact the author of the DarkRP Addon to fix this.
Until this is fixed you don't need to worry about anything. Everything will keep working.
It's just that registering DarkRPVars would make DarkRP faster.]], name), 4)
end
--[[---------------------------------------------------------------------------
Remove a player's DarkRPVar
---------------------------------------------------------------------------]]
function meta:removeDarkRPVar(var, target)
local vars = DarkRP.ServerDarkRPVars[self]
hook.Call("DarkRPVarChanged", nil, self, var, vars and vars[var], nil)
target = target or player.GetAll()
DarkRP.ServerDarkRPVars[self] = DarkRP.ServerDarkRPVars[self] or {}
DarkRP.ServerDarkRPVars[self][var] = nil
checkDarkRPVarRegistration(var)
net.Start("DarkRP_PlayerVarRemoval")
net.WriteUInt(self:UserID(), 16)
DarkRP.writeNetDarkRPVarRemoval(var)
net.Send(target)
end
--[[---------------------------------------------------------------------------
Set a player's DarkRPVar
---------------------------------------------------------------------------]]
function meta:setDarkRPVar(var, value, target)
target = target or player.GetAll()
if value == nil then return self:removeDarkRPVar(var, target) end
local vars = DarkRP.ServerDarkRPVars[self]
hook.Call("DarkRPVarChanged", nil, self, var, vars and vars[var], value)
DarkRP.ServerDarkRPVars[self] = DarkRP.ServerDarkRPVars[self] or {}
DarkRP.ServerDarkRPVars[self][var] = value
checkDarkRPVarRegistration(var)
net.Start("DarkRP_PlayerVar")
net.WriteUInt(self:UserID(), 16)
DarkRP.writeNetDarkRPVar(var, value)
net.Send(target)
end
--[[---------------------------------------------------------------------------
Set a private DarkRPVar
---------------------------------------------------------------------------]]
function meta:setSelfDarkRPVar(var, value)
DarkRP.ServerPrivateDarkRPVars[self] = DarkRP.ServerPrivateDarkRPVars[self] or {}
DarkRP.ServerPrivateDarkRPVars[self][var] = true
self:setDarkRPVar(var, value, self)
end
--[[---------------------------------------------------------------------------
Get a DarkRPVar
---------------------------------------------------------------------------]]
function meta:getDarkRPVar(var, fallback)
local vars = DarkRP.ServerDarkRPVars[self]
if vars == nil then return fallback end
local results = vars[var]
if results == nil then return fallback end
return results
end
--[[---------------------------------------------------------------------------
Backwards compatibility: Set ply.DarkRPVars attribute
---------------------------------------------------------------------------]]
function meta:setDarkRPVarsAttribute()
DarkRP.ServerDarkRPVars[self] = DarkRP.ServerDarkRPVars[self] or {}
-- With a reference to the table, ply.DarkRPVars should always remain
-- up-to-date. One needs only be careful that DarkRP.ServerDarkRPVars[ply]
-- is never replaced by a different table.
self.DarkRPVars = DarkRP.ServerDarkRPVars[self]
end
--[[---------------------------------------------------------------------------
Send the DarkRPVars to a client
---------------------------------------------------------------------------]]
function meta:sendDarkRPVars()
if self:EntIndex() == 0 then return end
local plys = player.GetAll()
net.Start("DarkRP_InitializeVars")
net.WriteUInt(#plys, 8)
for _, target in ipairs(plys) do
net.WriteUInt(target:UserID(), 16)
local vars = {}
for var, value in pairs(DarkRP.ServerDarkRPVars[target] or {}) do
if self ~= target and (DarkRP.ServerPrivateDarkRPVars[target] or {})[var] then continue end
table.insert(vars, var)
end
local vars_cnt = #vars
net.WriteUInt(vars_cnt, DarkRP.DARKRP_ID_BITS + 2) -- Allow for three times as many unknown DarkRPVars than the limit
for i = 1, vars_cnt, 1 do
DarkRP.writeNetDarkRPVar(vars[i], DarkRP.ServerDarkRPVars[target][vars[i]])
end
end
net.Send(self)
end
concommand.Add("_sendDarkRPvars", function(ply)
if ply.DarkRPVarsSent and ply.DarkRPVarsSent > (CurTime() - 3) then return end -- prevent spammers
ply.DarkRPVarsSent = CurTime()
ply:sendDarkRPVars()
end)
--[[---------------------------------------------------------------------------
Admin DarkRPVar commands
---------------------------------------------------------------------------]]
local function setRPName(ply, args)
if not args[2] or string.len(args[2]) < 2 or string.len(args[2]) > 30 then
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("invalid_x", DarkRP.getPhrase("arguments"), "<2/>30"))
return
end
local name = table.concat(args, " ", 2)
local target = DarkRP.findPlayer(args[1])
if not target then
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("could_not_find", args[1]))
return
end
local oldname = target:Nick()
DarkRP.retrieveRPNames(name, function(taken)
if not IsValid(target) then return end
if taken then
DarkRP.notify(ply, 1, 5, DarkRP.getPhrase("unable", "RPname", DarkRP.getPhrase("already_taken")))
return
end
DarkRP.storeRPName(target, name)
target:setDarkRPVar("rpname", name)
DarkRP.notify(ply, 0, 4, DarkRP.getPhrase("you_set_x_name", oldname, name))
local nick = ""
if ply:EntIndex() == 0 then
nick = "Console"
else
nick = ply:Nick()
end
DarkRP.notify(target, 0, 4, DarkRP.getPhrase("x_set_your_name", nick, name))
if ply:EntIndex() == 0 then
DarkRP.log("Console set " .. target:SteamName() .. "'s name to " .. name, Color(30, 30, 30))
else
DarkRP.log(ply:Nick() .. " (" .. ply:SteamID() .. ") set " .. target:SteamName() .. "'s name to " .. name, Color(30, 30, 30))
end
end)
end
DarkRP.definePrivilegedChatCommand("forcerpname", "DarkRP_AdminCommands", setRPName)
local function freerpname(ply, args)
local name = args ~= "" and args or IsValid(ply) and ply:Nick() or ""
MySQLite.query(("UPDATE darkrp_player SET rpname = NULL WHERE rpname = %s"):format(MySQLite.SQLStr(name)))
local nick = IsValid(ply) and ply:Nick() or "Console"
DarkRP.log(("%s has freed the rp name '%s'"):format(nick, name), Color(30, 30, 30))
DarkRP.notify(ply, 0, 4, ("'%s' has been freed"):format(name))
end
DarkRP.definePrivilegedChatCommand("freerpname", "DarkRP_AdminCommands", freerpname)
local function RPName(ply, args)
if ply.LastNameChange and ply.LastNameChange > (CurTime() - 5) then
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("have_to_wait", math.ceil(5 - (CurTime() - ply.LastNameChange)), "/rpname"))
return ""
end
if not GAMEMODE.Config.allowrpnames then
DarkRP.notify(ply, 1, 6, DarkRP.getPhrase("disabled", "/rpname", ""))
return ""
end
args = args:find"^%s*$" and '' or args:match"^%s*(.*%S)"
local canChangeName, reason = hook.Call("CanChangeRPName", GAMEMODE, ply, args)
if canChangeName == false then
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("unable", "/rpname", reason or ""))
return ""
end
ply:setRPName(args)
ply.LastNameChange = CurTime()
return ""
end
DarkRP.defineChatCommand("rpname", RPName)
DarkRP.defineChatCommand("name", RPName)
DarkRP.defineChatCommand("nick", RPName)
--[[---------------------------------------------------------------------------
Setting the RP name
---------------------------------------------------------------------------]]
function meta:setRPName(name, firstRun)
-- Make sure nobody on this server already has this RP name
local lowername = string.lower(tostring(name))
DarkRP.retrieveRPNames(name, function(taken)
if not IsValid(self) or string.len(lowername) < 2 and not firstrun then return end
-- If we found that this name exists for another player
if taken then
if firstRun then
-- If we just connected and another player happens to be using our steam name as their RP name
-- Put a 1 after our steam name
DarkRP.storeRPName(self, name .. " 1")
DarkRP.notify(self, 0, 12, DarkRP.getPhrase("someone_stole_steam_name"))
else
DarkRP.notify(self, 1, 5, DarkRP.getPhrase("unable", "/rpname", DarkRP.getPhrase("already_taken")))
return ""
end
else
if not firstRun then -- Don't save the steam name in the database
DarkRP.notifyAll(2, 6, DarkRP.getPhrase("rpname_changed", self:SteamName(), name))
DarkRP.storeRPName(self, name)
end
end
end)
end
--[[---------------------------------------------------------------------------
Maximum entity values
---------------------------------------------------------------------------]]
local maxEntities = {}
function meta:addCustomEntity(entTable)
maxEntities[self] = maxEntities[self] or {}
maxEntities[self][entTable.cmd] = maxEntities[self][entTable.cmd] or 0
maxEntities[self][entTable.cmd] = maxEntities[self][entTable.cmd] + 1
end
function meta:removeCustomEntity(entTable)
maxEntities[self] = maxEntities[self] or {}
maxEntities[self][entTable.cmd] = maxEntities[self][entTable.cmd] or 0
maxEntities[self][entTable.cmd] = maxEntities[self][entTable.cmd] - 1
end
function meta:customEntityLimitReached(entTable)
maxEntities[self] = maxEntities[self] or {}
maxEntities[self][entTable.cmd] = maxEntities[self][entTable.cmd] or 0
local max = entTable.getMax and entTable.getMax(self) or entTable.max
return max ~= 0 and maxEntities[self][entTable.cmd] >= max
end
function meta:customEntityCount(entTable)
local entities = maxEntities[self]
if entities == nil then return 0 end
entities = entities[entTable.cmd]
if entities == nil then return 0 end
return entities
end
-- We use EntityRemoved to clear players of tables, because it is always called
-- after the PlayerDisconnected hook. This is called _after_ the GAMEMODE
-- function, to make sure that all regular hooks can still use DarkRPVars until
-- the very end. See https://github.com/FPtje/DarkRP/pull/3270
(GAMEMODE or GM).DarkRPPostEntityRemoved = function(_gm, ent)
if not ent:IsPlayer() then return end
maxEntities[ent] = nil
DarkRP.ServerDarkRPVars[ent] = nil
DarkRP.ServerPrivateDarkRPVars[ent] = nil
net.Start("DarkRP_DarkRPVarDisconnect")
net.WriteUInt(ent:UserID(), 16)
net.Broadcast()
end