347 lines
8.5 KiB
Lua
347 lines
8.5 KiB
Lua
dbgEstates = dbgEstates or {}
|
|
dbgEstates.data = dbgEstates.data or {}
|
|
local empty = {}
|
|
local toRem = {}
|
|
|
|
local radius, limit = 5, 15
|
|
local sides = { Vector(1,0,0), Vector(-1,0,0), Vector(0,1,0), Vector(0,-1,0), Vector(0,0,1), Vector(0,0,-1) }
|
|
local function getDoorPos(ent)
|
|
local entPos = ent:GetPos()
|
|
if table.HasValue(ents.FindInSphere(entPos, radius), ent) then return entPos end
|
|
|
|
for i = 0, limit do
|
|
local delta = radius * 2 * i
|
|
for _, side in ipairs(sides) do
|
|
pos = entPos + side * delta
|
|
if table.HasValue(ents.FindInSphere(pos, radius), ent) then return pos end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function nextAvailable()
|
|
local nxt, estIdx = 1
|
|
while not estIdx do
|
|
estIdx = not dbgEstates.data[nxt] and nxt or nil
|
|
nxt = nxt + 1
|
|
end
|
|
return estIdx
|
|
end
|
|
|
|
local planDBUpdate = octolib.func.debounce(function()
|
|
local all = {}
|
|
for _,v in ipairs(toRem) do
|
|
all[#all + 1] = v
|
|
end
|
|
table.Empty(toRem)
|
|
for k,v in pairs(dbgEstates.data) do
|
|
local tbl = table.Copy(v)
|
|
tbl.owners = {}
|
|
tbl.doors = {}
|
|
for _,owner in ipairs(v.owners or {}) do
|
|
if not octolib.string.isSteamID(owner) then
|
|
tbl.owners[#tbl.owners + 1] = owner
|
|
end
|
|
end
|
|
for _,door in ipairs(v.doors or {}) do
|
|
tbl.doors[#tbl.doors + 1] = {
|
|
getDoorPos(door) or door:MapCreationID(),
|
|
door.title,
|
|
}
|
|
end
|
|
all[#all + 1] = {k, tbl}
|
|
end
|
|
octolib.func.throttle(all, 5, 0.5, function(nxt)
|
|
if isnumber(nxt) then
|
|
octolib.db:PrepareQuery([[DELETE FROM `dbg_estates` WHERE `id`=?]], {nxt})
|
|
else
|
|
local k, v = unpack(nxt)
|
|
local dat = pon.encode(v or {})
|
|
octolib.db:PrepareQuery([[INSERT INTO `dbg_estates` (`id`, `map`, `data`) VALUES (?,?,?) ON DUPLICATE KEY UPDATE `data`=?]],
|
|
{k, game.GetMap(), dat, dat})
|
|
end
|
|
end)
|
|
end, 0)
|
|
|
|
local updateNW = octolib.func.debounce(function()
|
|
netvars.SetNetVar('dbg-estates', dbgEstates.data)
|
|
end, 0)
|
|
|
|
-- unlinks the door from estates
|
|
local function removeFromPreviousEstate(door)
|
|
local curEst = door:GetNetVar('estate')
|
|
if curEst and dbgEstates.data[curEst] and dbgEstates.data[curEst].doors then
|
|
table.RemoveByValue(dbgEstates.data[curEst].doors, door)
|
|
if not dbgEstates.data[curEst].doors[1] then
|
|
dbgEstates.data[curEst] = nil
|
|
toRem[#toRem + 1] = curEst
|
|
updateNW()
|
|
planDBUpdate()
|
|
end
|
|
end
|
|
door:SetNetVar('estate')
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Sets specified price for estate and saves it
|
|
]]
|
|
function dbgEstates.setEstatePrice(estIdx, price)
|
|
if not isnumber(price) or price < 0 then return end
|
|
if not dbgEstates.data[estIdx] then return end
|
|
dbgEstates.data[estIdx].price = price
|
|
updateNW()
|
|
planDBUpdate()
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Sets estate purpose of estate and saves it
|
|
0 - both business and residency
|
|
1 - business only
|
|
2 - residency only
|
|
]]
|
|
function dbgEstates.setPurpose(estIdx, purpose)
|
|
if not purpose then purpose = 0 end
|
|
if not (isnumber(purpose) and octolib.math.inRange(purpose, 0, 2)) then return end
|
|
if not dbgEstates.data[estIdx] then return end
|
|
if purpose == 0 then
|
|
dbgEstates.data[estIdx].purpose = nil
|
|
else
|
|
dbgEstates.data[estIdx].purpose = purpose
|
|
end
|
|
updateNW()
|
|
planDBUpdate()
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Sets marker position for estate and saves it
|
|
]]
|
|
function dbgEstates.updateMarker(estIdx, pos)
|
|
if pos ~= nil and not istable(pos) then return end
|
|
if not dbgEstates.data[estIdx] then return end
|
|
dbgEstates.data[estIdx].marker = pos
|
|
updateNW()
|
|
planDBUpdate()
|
|
end
|
|
|
|
--[[
|
|
(table)
|
|
Returns estate's data,
|
|
or empty table if doesn't exist.
|
|
You should NOT modify this!
|
|
]]
|
|
function dbgEstates.getData(estIdx)
|
|
return dbgEstates.data[estIdx] or empty
|
|
end
|
|
|
|
--[[
|
|
(bool)
|
|
Returns wether estate with this id exists
|
|
]]
|
|
function dbgEstates.exists(estIdx)
|
|
return dbgEstates.data[estIdx] ~= nil
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Forces something to own an estate.
|
|
Can be:
|
|
'STEAM_X:Y:Z' for player (removes any current SteamID owners)
|
|
'g:command' for organization (e.g. police)
|
|
'j:command' for job (e.g. mayor)
|
|
]]
|
|
function dbgEstates.addOwner(estIdx, owner)
|
|
if not estIdx or not dbgEstates.data[estIdx] then return end
|
|
dbgEstates.data[estIdx].owners = dbgEstates.data[estIdx].owners or {}
|
|
|
|
local owners = dbgEstates.data[estIdx].owners
|
|
if table.HasValue(owners, owner) then return false end
|
|
|
|
local isPly = octolib.string.isSteamID(owner)
|
|
if isPly then -- there can be only one player owner
|
|
for i = #owners, 1, -1 do
|
|
if octolib.string.isSteamID(owners[i]) then
|
|
table.remove(owners, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
owners[#owners + 1] = owner
|
|
updateNW()
|
|
if not isPly then planDBUpdate() end
|
|
|
|
return true
|
|
end
|
|
|
|
--[[
|
|
(bool)
|
|
Forces something to unown an estate.
|
|
Can be:
|
|
'STEAM_X:Y:Z' for player (removes any current SteamID owners)
|
|
'g:command' for organization (e.g. police)
|
|
'j:command' for job (e.g. mayor)
|
|
]]
|
|
function dbgEstates.removeOwner(estIdx, owner)
|
|
if not estIdx or not dbgEstates.data[estIdx] then return end
|
|
dbgEstates.data[estIdx].owners = dbgEstates.data[estIdx].owners or {}
|
|
|
|
local owns = dbgEstates.data[estIdx].owners
|
|
local removed = table.RemoveByValue(owns, owner)
|
|
if removed then
|
|
if not octolib.string.isSteamID(owner) then
|
|
planDBUpdate()
|
|
else
|
|
for _,v in ipairs(dbgEstates.data[estIdx].doors or empty) do
|
|
v:SetNetVar('tempTitle', v.title)
|
|
v:DoLock()
|
|
end
|
|
end
|
|
updateNW()
|
|
end
|
|
|
|
return tobool(removed)
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Changes owners of an estate.
|
|
Please use it only if you know what you do!
|
|
]]
|
|
function dbgEstates.updateOwners(estIdx, owners)
|
|
if (owners ~= nil and not istable(owners)) or not estIdx or not dbgEstates.data[estIdx] then return end
|
|
dbgEstates.data[estIdx].owners = owners or {}
|
|
planDBUpdate()
|
|
updateNW()
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Saves everything to database
|
|
]]
|
|
function dbgEstates.planDBUpdate()
|
|
planDBUpdate()
|
|
end
|
|
|
|
--[[
|
|
(bool)
|
|
Links door to a new estate
|
|
]]
|
|
function dbgEstates.linkDoor(door, estIdx)
|
|
if not IsEntity(door) or not door:IsDoor() then return end
|
|
if not dbgEstates.exists(estIdx) then return end
|
|
dbgEstates.data[estIdx].doors = dbgEstates.data[estIdx].doors or {}
|
|
dbgEstates.data[estIdx].doors[#dbgEstates.data[estIdx].doors + 1] = door
|
|
door:SetNetVar('estate', estIdx)
|
|
if not dbgEstates.data[estIdx].owners[1] then
|
|
door:DoLock()
|
|
end
|
|
updateNW()
|
|
planDBUpdate()
|
|
return true
|
|
end
|
|
|
|
--[[
|
|
(void)
|
|
Removes a door from any estates so that
|
|
it can't be owned by anyone.
|
|
]]
|
|
function dbgEstates.unlinkDoor(door)
|
|
if not IsEntity(door) or not door:IsDoor() then return end
|
|
removeFromPreviousEstate(door)
|
|
door:DoUnlock()
|
|
if door.title then -- we want to save title so we move it to a zero estate
|
|
dbgEstates.data[0] = dbgEstates.data[0] or {
|
|
doors = {},
|
|
price = 0,
|
|
owners = {},
|
|
name = 'Заблокированные',
|
|
}
|
|
dbgEstates.linkDoor(door, 0)
|
|
else
|
|
updateNW()
|
|
planDBUpdate()
|
|
end
|
|
end
|
|
|
|
--[[
|
|
(int)
|
|
Moves door to a new estate with only this door
|
|
and returns ID of the new estate.
|
|
]]
|
|
function dbgEstates.createEstate(door, name)
|
|
if not IsEntity(door) or not door:IsDoor() then return end
|
|
removeFromPreviousEstate(door)
|
|
local estIdx = nextAvailable()
|
|
dbgEstates.data[estIdx] = {
|
|
doors = {door},
|
|
price = GAMEMODE.Config.doorcost or 50,
|
|
owners = {},
|
|
name = tostring(name),
|
|
}
|
|
door:SetNetVar('estate', estIdx)
|
|
door:DoLock()
|
|
updateNW()
|
|
planDBUpdate()
|
|
return estIdx
|
|
end
|
|
|
|
function dbgEstates.getNearest(pos)
|
|
local nearest = math.huge
|
|
local nearestid = 0
|
|
|
|
for i, est in pairs(dbgEstates.data) do
|
|
for id, ent in pairs(est.doors) do
|
|
if not IsValid(ent) then continue end
|
|
local dis = ent:GetPos():DistToSqr(pos)
|
|
if dis < nearest then
|
|
nearest = dis
|
|
nearestid = i
|
|
end
|
|
end
|
|
end
|
|
return dbgEstates.data[nearestid]
|
|
end
|
|
|
|
hook.Add('octolib.db.init', 'dbg-premises.init', function()
|
|
|
|
octolib.db:RunQuery([[CREATE TABLE IF NOT EXISTS `dbg_estates` (
|
|
`id` INT UNSIGNED NOT NULL,
|
|
`map` VARCHAR(50) NOT NULL,
|
|
`data` TEXT NULL,
|
|
PRIMARY KEY (`id`, `map`)
|
|
)]])
|
|
|
|
dbgEstates.data = {}
|
|
octolib.db:PrepareQuery([[SELECT * FROM `dbg_estates` WHERE `map`=?]], {game.GetMap()}, function(q, st, res)
|
|
if not istable(res) or not res[1] then return end
|
|
for _,v in ipairs(res) do
|
|
local dat = pon.decode(v.data or '[}') or {}
|
|
if dat.doors then
|
|
for i = 1, #dat.doors do
|
|
local ent
|
|
local posOrID = dat.doors[i][1]
|
|
if isnumber(posOrID) then
|
|
-- ent = ents.GetMapCreatedEntity(posOrID)
|
|
else
|
|
for _, e in ipairs(ents.FindInSphere(dat.doors[i][1], radius)) do
|
|
if IsValid(e) and e:IsDoor() then ent = e break end
|
|
end
|
|
end
|
|
|
|
local title = dat.doors[i][2]
|
|
dat.doors[i] = ent
|
|
if not ent then continue end
|
|
|
|
ent:SetNetVar('estate', v.id)
|
|
ent.title = title
|
|
ent:SetNetVar('tempTitle', title)
|
|
ent:DoLock()
|
|
end
|
|
end
|
|
dbgEstates.data[v.id] = dat
|
|
end
|
|
updateNW()
|
|
end)
|
|
|
|
end)
|