Files
2026-03-31 10:27:04 +03:00

974 lines
29 KiB
Lua

if (!SH_REPORTS.ActiveReports) then
SH_REPORTS.ActiveReports = {}
SH_REPORTS.UniqueID = 0
SH_REPORTS.InsertSQL = "INSERT IGNORE INTO"
end
if (SH_REPORTS.UseWorkshop) then
-- resource.AddWorkshop("1141886968")
else
resource.AddFile("materials/shenesis/general/back.png")
resource.AddFile("materials/shenesis/general/close.png")
resource.AddFile("materials/shenesis/reports/add.png")
resource.AddFile("materials/shenesis/reports/stats.png")
resource.AddFile("materials/shenesis/reports/star.png")
resource.AddFile("resource/fonts/circular.ttf")
resource.AddFile("resource/fonts/circular_bold.ttf")
end
function SH_REPORTS:DatabaseConnected()
if (self.DatabaseMode == "mysqloo") then
self:Query("SHOW TABLES LIKE 'sh_reports_performance'", function(q, ok, data)
if (!ok) or (data and table.Count(data) > 0) then
self:PostDatabaseConnected()
return
end
self:Query([[
CREATE TABLE `sh_reports_performance` (
`steamid` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`claimed` int(10) unsigned DEFAULT '0',
`closed` int(10) unsigned DEFAULT '0',
`timespent` int(10) unsigned DEFAULT '0',
`report_id` int(10) unsigned DEFAULT '0',
UNIQUE KEY `steamid_UNIQUE` (`steamid`,`report_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `sh_reports_performance_reports` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`start_time` int(10) unsigned DEFAULT '0',
`end_time` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
]], function(q2, ok2, data2)
self:DBPrint("Creating sh_reports_performance and sh_reports_performance_reports: " .. tostring(ok2) .. " (" .. tostring(data2) /* 76561198398853149 */ .. ")")
self:PostDatabaseConnected()
end)
end)
self:Query("SHOW TABLES LIKE 'sh_reports_performance_ratings'", function(q, ok, data)
if (!ok) or (data and table.Count(data) > 0) then
return end
self:Query([[
CREATE TABLE `sh_reports_performance_ratings` (
`steamid` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`total` int(10) unsigned DEFAULT '0',
`num` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`steamid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
]], function(q2, ok2, data2)
self:DBPrint("Creating sh_reports_performance_ratings: " .. tostring(ok2) .. " (" .. tostring(data2) /* 76561198398853124 */ .. ")")
end)
end)
self:Query("SHOW TABLES LIKE 'sh_reports_performance_history'", function(q, ok, data)
if (!ok) or (data and table.Count(data) > 0) then
return end
self:Query([[
CREATE TABLE `sh_reports_performance_history` (
`id` int(10) unsigned NOT NULL,
`reporter` varchar(64) NOT NULL,
`reported` varchar(64) NOT NULL,
`reason` varchar(256),
`comment` varchar(2048),
`waiting_time` int(10) unsigned DEFAULT '0',
`date` int(10) unsigned DEFAULT '0',
`admin` varchar(64) NOT NULL,
`rating` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
]], function(q2, ok2, data2)
self:DBPrint("Creating sh_reports_performance_history: " .. tostring(ok2) .. " (" .. tostring(data2) .. ")")
end)
end)
else
local function CreateTable(name, query)
if (!sql.TableExists(name)) then
sql.Query([[
CREATE TABLE `]] .. name .. [[` (]] .. query .. [[)
]])
self:DBPrint("Creating " .. name .. ": " .. tostring(sql.TableExists(name)))
end
end
CreateTable("sh_reports_performance", [[
`steamid` varchar(64) NOT NULL,
`claimed` int(10) DEFAULT '0',
`closed` int(10) DEFAULT '0',
`timespent` int(10) DEFAULT '0',
`report_id` int(10) DEFAULT '0',
UNIQUE(steamid, report_id) ON CONFLICT IGNORE
]])
CreateTable("sh_reports_performance_reports", [[
`id` int(10) NOT NULL PRIMARY KEY,
`start_time` int(10) DEFAULT '0',
`end_time` int(10) DEFAULT '0'
]])
CreateTable("sh_reports_performance_ratings", [[
`steamid` varchar(64) NOT NULL PRIMARY KEY,
`total` int(10) DEFAULT '0',
`num` int(10) DEFAULT '0'
]])
CreateTable("sh_reports_performance_history", [[
`id` int(10) NOT NULL PRIMARY KEY,
`reporter` varchar(64) NOT NULL,
`reported` varchar(64) NOT NULL,
`reason` varchar(256),
`comment` varchar(2048),
`waiting_time` int(10) DEFAULT '0',
`date` int(10) DEFAULT '0',
`admin` varchar(64) NOT NULL,
`rating` int(5) DEFAULT '0'
]])
self.InsertSQL = "INSERT OR IGNORE INTO"
self:PostDatabaseConnected()
end
end
function SH_REPORTS:PostDatabaseConnected()
self:BetterQuery("SELECT * FROM sh_reports_performance_reports WHERE {time} < end_time ORDER BY id DESC", {time = os.time()}, function(q, ok, data)
if (!ok) then
return end
if (data and #data > 0) then
local d = table.Copy(data[1])
d.id = tonumber(d.id)
d.start_time = tonumber(d.start_time)
d.end_time = tonumber(d.end_time)
self.CurrentPerfReport = d
self:DBPrint("Using performance report #" .. d.id .. ". It will last until " .. os.date(self.DateFormat, d.end_time) .. " 00:00.")
else
self:DBPrint("Creating new performance report as none were found.")
self:CreatePerformanceReport()
end
end)
if (self.StorageExpiryTime > 0) then
self:BetterQuery("DELETE FROM sh_reports_performance_history WHERE {time} > date", {time = os.time() - self.StorageExpiryTime})
end
end
function SH_REPORTS:CreatePerformanceReport()
local days = 1
if (self.PerformanceFrequency == "weekly") then
days = 7 - tonumber(os.date("%w")) + self.PerformanceWeekDay
elseif (self.PerformanceFrequency == "monthly") then
days = 31
end
local mthen = self:GetMidnight(days)
self:Query("SELECT id FROM sh_reports_performance_reports", function(q, ok, data)
if (!ok) then
return end
local d = {id = table.Count(data) + 1, start_time = os.time(), end_time = mthen}
self.CurrentPerfReport = d
self:BetterQuery([[
INSERT INTO sh_reports_performance_reports (id, start_time, end_time)
VALUES ({id}, {start_time}, {end_time})
]], d)
self:DBPrint("Created performance report #" .. d.id .. ". It will last until " .. os.date(self.DateFormat, mthen) .. " 00:00.")
end)
self.CachedPerfReports = nil
end
function SH_REPORTS:NewReport(ply, data)
if (self:IsAdmin(ply) and !self.StaffCanReport) then
self:Notify(ply, "cannot_report_as_admin", false)
return
end
if (data.reporter_id == data.reported_id) then
self:Notify(ply, "cannot_report_self", false)
return
end
local target = player.GetBySteamID64(data.reported_id)
if (IsValid(target) and self:IsAdmin(target) and !self.StaffCanBeReported) then
self:Notify(ply, "cannot_report_admin", false)
return
end
local sid = ply:SteamID64()
if (table.Count(self:GetAllReports(sid)) >= self.MaxReportsPerPlayer) then
self:Notify(ply, "report_limit_reached", false)
return
end
if (data.reported_id == "0" and !self.CanReportOther) then
return end
self.UniqueID = self.UniqueID + 1
data.id = self.UniqueID
self.ActiveReports[data.id] = table.Copy(data)
self:Notify(ply, "report_submitted", true)
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> reported [#" .. data.id .. "] " .. data.reported_name .. " <" .. util.SteamIDFrom64(data.reported_id /* 76561198398853124 */) .. "> for " .. self.ReportReasons[data.reason_id])
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportCreated", data)
end
function SH_REPORTS:PlayerSay(ply, str)
local text = str:Replace("!", "/"):lower():Trim()
if (self.AdminCommands[text]) then
self:ShowReports(ply)
return ""
end
if (self.ReportCommands[text]) then
if (!self:IsAdmin(ply) or self.StaffCanReport) then
easynet.Send(ply, "SH_REPORTS.QuickReport", {comment = "", lastkiller = ply.SH_LastKiller, lastarrester = ply.SH_LastArrester})
else
self:Notify(ply, "cannot_report_as_admin", false)
end
return ""
end
if (self.EnableQuickReport and !self:IsAdmin(ply) and text:StartWith("@")) then
easynet.Send(ply, "SH_REPORTS.QuickReport", {comment = str:sub(2), lastkiller = ply.SH_LastKiller, lastarrester = ply.SH_LastArrester})
return ""
end
if (text == "/reportstats") then
if (self:IsAdmin(ply)) then
self:BetterQuery("SELECT * FROM sh_reports_performance WHERE steamid = {steamid}", {steamid = ply:SteamID64()}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
local claimed = 0
local closed = 0
for _, d in pairs (data) do
claimed = claimed + tonumber(d.claimed)
closed = closed + tonumber(d.closed)
end
ply:ChatPrint("Reports claimed: " .. string.Comma(claimed) .. " | Reports closed: " .. string.Comma(closed))
end)
end
return ""
end
end
function SH_REPORTS:ShowReports(ply)
local tosend = {}
if (self:IsAdmin(ply)) then -- If admin, send all reports, if not only send own
tosend = self:GetAllReports()
else
tosend = self:GetAllReports(ply:SteamID64())
end
easynet.Send(ply, "SH_REPORTS.SendList", {
server_time = os.time(),
struct_reports = tosend,
})
end
local function SendPerfReports(ply, preps)
easynet.Send(ply, "SH_REPORTS.SendPerfReports", {
struct_perf_reports = preps
})
end
function SH_REPORTS:ShowPerformanceReports(ply)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
if (self.CachedPerfReports) then
SendPerfReports(ply, self.CachedPerfReports)
else
self:BetterQuery("SELECT * FROM sh_reports_performance_reports", {time = os.time()}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
local d = {}
for k, v in pairs (data) do
d[tonumber(v.id)] = v
end
self.CachedPerfReports = d
if (IsValid(ply)) then
SendPerfReports(ply, d)
end
end)
end
end
function SH_REPORTS:RequestPerfReportStaff(ply, id)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
self:BetterQuery("SELECT steamid, claimed, closed, timespent FROM sh_reports_performance WHERE report_id = {id}" /* 76561198398853149 */, {id = id}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
for k, v in pairs (data) do
v.claimed = tonumber(v.claimed) or 0
v.closed = tonumber(v.closed) or 0
v.timespent = tonumber(v.timespent) or 0
end
easynet.Send(ply, "SH_REPORTS.SendPerfReportStaff", {
id = id,
struct_perf_reports_staff = data
})
end)
end
function SH_REPORTS:RequestStaffRatings(ply)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
self:BetterQuery("SELECT steamid, num, total FROM sh_reports_performance_ratings" /* 76561198398853124 */, {}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
easynet.Send(ply, "SH_REPORTS.SendRatings", {
struct_rating = data
})
end)
end
function SH_REPORTS:RequestReportHistory(ply)
if (!self.UsergroupsPerformance[ply:GetUserGroup()]) then
self:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
self:BetterQuery("SELECT * FROM sh_reports_performance_history", {}, function(q, ok, data)
if (!ok or !IsValid(ply)) then
return end
-- Factorize the SteamID's to save on bytes
local t_steamids = {}
local t = {}
for _, dat in pairs (data) do
t[tonumber(dat.id)] = dat
t_steamids[dat.reporter] = true
t_steamids[dat.reported] = true
t_steamids[dat.admin] = true
end
local steamids = {}
for steamid in pairs (t_steamids) do
t_steamids[steamid] = table.insert(steamids, {steamid = steamid})
end
local t_list = {}
for id, dat in pairs (t) do
table.insert(t_list, {
report_id = tonumber(dat.id),
reporter_nid = t_steamids[dat.reporter],
reported_nid = t_steamids[dat.reported],
reason = dat.reason,
comment = dat.comment,
rating = dat.rating,
date = dat.date,
waiting_time = dat.waiting_time,
admin_nid = t_steamids[dat.admin],
})
end
easynet.Send(ply, "SH_REPORTS.SendHistoryList", {
struct_history_steamids = steamids,
struct_history_list = t_list,
})
end)
end
function SH_REPORTS:ClaimReport(admin, report)
local sid = admin:SteamID64()
for _, rep in pairs (self:GetAllReports()) do
if (rep.admin_id == sid) then
self:Notify(admin, "claimed_report_still_active", false)
return false
end
end
if (report.admin_id ~= "") then
return false
end
report.claim_time = os.time()
report.admin_id = sid
self:Notify(player.GetBySteamID64(report.reporter_id), "admin_claimed_your_report", true)
easynet.Send(admin, "SH_REPORTS.MinimizeReport", {report_id = report.id})
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportClaimed", {report_id = report.id, admin_id = report.admin_id})
if (self.CurrentPerfReport) and (!report.is_admin or self.AdminReportsCount) then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance (steamid, report_id)
VALUES ({steamid}, {report_id});
UPDATE sh_reports_performance SET claimed = claimed + 1
WHERE steamid = {steamid} AND report_id = {report_id}
]], {steamid = admin:SteamID64(), report_id = self.CurrentPerfReport.id})
end
return true
end
function SH_REPORTS:ClaimAndTeleport(admin, id, bring, bring_reported)
if (!self:IsAdmin(admin)) then
self:Notify(admin, "not_allowed_to_run_cmd", false)
return
end
local report = self:FindReport(id)
if (!report) then
self:Notify(admin, "report_non_existent", false)
return
end
if (self.ClaimNoTeleport) then
return end
local target = player.GetBySteamID64(report.reporter_id)
if (!IsValid(target)) then
return end
if (!self:ClaimReport(admin, report)) then
return end
admin.SH_PosBeforeReport = admin:GetPos()
target.SH_PosBeforeReport = target:GetPos()
if (self.UseULXCommands) then
-- Bad idea? ULX sucks anyways
if (bring) then
ulx.bring(admin, {target})
else
ulx.goto(admin, target)
end
if (bring_reported) then
local reported = player.GetBySteamID64(report.reported_id)
if (IsValid(reported)) then
reported.SH_PosBeforeReport = reported:GetPos()
if (bring) then
ulx.bring(admin, {reported})
else
ulx.send(admin, reported, target)
end
end
end
else
local a, b = admin, target
if (bring) then
a, b = target, admin
end
self:TeleportPlayer(a, b:GetPos())
if (bring_reported) then
local reported = player.GetBySteamID64(report.reported_id)
if (IsValid(reported)) then
reported.SH_PosBeforeReport = reported:GetPos()
self:TeleportPlayer(reported, b:GetPos())
end
end
end
self:Log(admin:Nick() .. " <" .. admin:SteamID() .. "> claimed " .. target:Nick() .. "'s <" .. target:SteamID() .. "> report [#" .. id .. "]")
end
function SH_REPORTS:ClaimAndCSit(admin, id)
if (!csitsystem) then
return end
if (!self:IsAdmin(admin)) then
self:Notify(admin, "not_allowed_to_run_cmd", false)
return
end
local report = self:FindReport(id)
if (!report) then
self:Notify(admin, "report_non_existent", false)
return
end
local target = player.GetBySteamID64(report.reporter_id)
if (!IsValid(target)) then
return end
if (!self:ClaimReport(admin, report)) then
return end
admin.SH_PosBeforeReport = admin:GetPos()
target.SH_PosBeforeReport = target:GetPos()
report.sit_id = csitsystem.HandOver(admin, target, player.GetBySteamID64(report.reported_id))
self:Log(admin:Nick() .. " <" .. admin:SteamID() .. "> claimed " .. target:Nick() .. "'s <" .. target:SteamID() .. "> report [#" .. id .. "] and started a sit")
-- self:CloseReport(admin, id)
end
function SH_REPORTS:CloseReport(ply, id)
local report = self:FindReport(id)
if (!report) then
self:Notify(ply, "report_non_existent", false)
return
end
local sid = ply:SteamID64()
if (self:IsAdmin(ply) and ((report.admin_id == "" and self.CanDeleteWhenUnclaimed) or report.admin_id == sid)) or (report.reporter_id == sid) then
self.ActiveReports[id] = nil
self:Notify(ply, "report_closed", true)
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportClosed", {report_id = id})
local target = player.GetBySteamID64(report.reporter_id)
local admin = player.GetBySteamID64(report.admin_id)
if (IsValid(target)) then
if (report.reporter_id ~= sid) then
self:Notify(target, "your_report_was_closed", true)
elseif (report.admin_id ~= "") then
if (IsValid(admin) and admin ~= ply) then
self:Notify(admin, "reporter_closed_report", true)
end
end
easynet.Send(target, "SH_REPORTS.ReportClosed", {report_id = id})
end
if (!report.is_admin or self.AdminReportsCount) then
if (report.admin_id ~= "") then
local claim_time = os.time() - report.claim_time
if (self.CurrentPerfReport) then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance (steamid, report_id, timespent)
VALUES ({steamid}, {report_id}, {timespent});
UPDATE sh_reports_performance SET closed = closed + 1, timespent = timespent + {timespent}
WHERE steamid = {steamid} AND report_id = {report_id}
]], {steamid = report.admin_id, report_id = self.CurrentPerfReport.id, timespent = claim_time})
end
if (sid == report.reporter_id) then
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed their own report [#" .. id .. "]")
else
if (IsValid(target) and self.AskRating) then
if (!target.SH_ReportsCompleted) then
target.SH_ReportsCompleted = {}
end
target.SH_ReportsCompleted[id] = ply:SteamID64()
easynet.Send(target, "SH_REPORTS.PromptRating", {report_id = id, admin_name = ply:Nick()})
end
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed the report [#" .. id .. "] from " .. report.reporter_name .. "<" .. util.SteamIDFrom64(report.reporter_id) .. ">")
end
elseif (self:IsAdmin(ply)) then
if (self.CurrentPerfReport) then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance (steamid, report_id)
VALUES ({steamid}, {report_id});
UPDATE sh_reports_performance SET closed = closed + 1
WHERE steamid = {steamid} AND report_id = {report_id}
]], {steamid = sid, report_id = self.CurrentPerfReport.id})
end
if (sid == report.reporter_id) then
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed their own UNCLAIMED report [#" .. id .. "]")
else
self:Log(ply:Nick() .. " <" .. ply:SteamID() .. "> closed the UNCLAIMED report [#" .. id .. "] from " .. report.reporter_name .. "<" .. util.SteamIDFrom64(report.reporter_id) .. ">")
end
end
end
if (report.admin_id ~= "") then
if (report.sit_id) then
csitsystem.EndSit(report.sit_id)
end
if (self.TeleportPlayersBack) then
if (IsValid(target)) then
self:ReturnPlayer(target)
end
local admin = player.GetBySteamID64(report.admin_id)
if (IsValid(admin)) then
self:ReturnPlayer(admin)
end
local reported = player.GetBySteamID64(report.reported_id)
if (IsValid(reported)) then
self:ReturnPlayer(reported)
end
end
if (self.StoreCompletedReports ~= "none") then
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance_history (id, reporter, reported, reason, comment, waiting_time, date, admin)
VALUES ({id}, {reporter}, {reported}, {reason}, {comment}, {waiting_time}, {date}, {admin});
]], {id = id, reporter = report.reporter_id, reported = report.reported_id, reason = self.ReportReasons[report.reason_id], comment = report.comment, waiting_time = os.time() - report.time, date = os.time(), admin = report.admin_id})
end
end
else
self:Notify(ply, "not_allowed_to_run_cmd", false)
end
end
function SH_REPORTS:RateAdmin(ply, report_id, rating)
if (!ply.SH_ReportsCompleted or !ply.SH_ReportsCompleted[report_id]) then
self:Notify(ply, "report_non_existent", false)
return
end
local admin_id = ply.SH_ReportsCompleted[report_id]
rating = math.Clamp(rating, 1, 5)
self:BetterQuery([[
]] .. self.InsertSQL .. [[ sh_reports_performance_ratings (steamid, total, num)
VALUES ({steamid}, 0, 0);
UPDATE sh_reports_performance_ratings SET total = total + {rating}, num = num + 1
WHERE steamid = {steamid}
]], {steamid = admin_id, rating = rating})
if (self.StoreCompletedReports ~= "none") then
self:BetterQuery([[
UPDATE sh_reports_performance_history SET rating = {rating}
WHERE id = {id}
]], {id = report_id, rating = rating})
end
if (self.NotifyRating) then
local admin = player.GetBySteamID64(admin_id)
if (IsValid(admin)) then
local rstr = ""
for i = 1, 5 do
rstr = rstr .. (rating >= i and "" or "")
end
self:Notify(admin, "rate_notification\t" .. ply:Nick() .. "\t" .. rstr, rating >= 3)
end
end
ply.SH_ReportsCompleted[report_id] = nil
self:Notify(ply, "rate_thanks", true)
end
function SH_REPORTS:PlayerReady(ply)
if (self.NotifyAdminsOnConnect and self:IsAdmin(ply)) then
local num = 0
local pending = {}
for id, report in pairs (self:GetAllReports()) do
if (report.admin_id == "") then
num = num + 1
table.insert(pending, report)
end
end
if (num > 0) then
easynet.Send(ply, "SH_REPORTS.ReportsPending", {num = num, struct_reports = pending})
end
end
end
function SH_REPORTS:PlayerDisconnected(ply)
local sid = ply:SteamID64()
for id, report in pairs (self:GetAllReports()) do
if (report.reporter_id == sid) then
self.ActiveReports[id] = nil
easynet.Send(self:GetStaff(), "SH_REPORTS.ReportClosed", {report_id = id})
local admin = player.GetBySteamID64(report.admin_id)
if (IsValid(admin)) then
self:Notify(admin, "reporter_closed_report", false)
end
elseif (self:IsAdmin(ply) and report.admin_id == sid) then
report.admin_id = ""
easynet.Send(self:GetStaff(), "SH_REPORTS.AdminLeft", {report_id = id})
local reporter = player.GetBySteamID64(report.reporter_id)
if (IsValid(reporter)) then
easynet.Send(reporter, "SH_REPORTS.AdminLeft", {report_id = id})
self:Notify(reporter, "admin_has_disconnected", false)
end
end
end
end
function SH_REPORTS:ReturnPlayer(ply)
if (!ply.SH_PosBeforeReport) then
return end
ply:SetPos(ply.SH_PosBeforeReport)
ply.SH_PosBeforeReport = nil
end
function SH_REPORTS:MidnightCheck()
local perf = self.CurrentPerfReport
if (!perf) then
return end
if (os.time() >= perf.end_time) then
self:DBPrint("Current performance report #" .. perf.id .. " expired, creating new one..")
self:CreatePerformanceReport()
end
end
function SH_REPORTS:Notify(ply, msg, good)
easynet.Send(ply, "SH_REPORTS.Notify", {msg = msg, positive = good})
end
function SH_REPORTS:GetStaff(ply)
local t = {}
for _, v in ipairs (player.GetAll()) do
if (self:IsAdmin(v)) then
table.insert(t, v)
end
end
return t
end
local function CheckObstruction(ply, pos)
local t = {
start = pos,
endpos = pos + Vector(0, 0, 72),
mins = Vector(-16, -16, 0),
maxs = Vector(16, 16, 4),
filter = ply
}
return bit.band(util.PointContents(pos), CONTENTS_SOLID) > 0 or util.TraceHull(t).Hit
end
local coords = {
Vector(48, 0, 0),
Vector(-48, 0, 0),
Vector(0, 48, 0),
Vector(0, -48, 0),
Vector(48, 48, 0),
Vector(-48, 48, 0),
Vector(48, -48, 0),
Vector(-48, -48, 0),
}
function SH_REPORTS:TeleportPlayer(ply, pos, exact)
if (!exact) then
if (CheckObstruction(ply, pos)) then
for _, c in ipairs (coords) do
if (!util.TraceLine({start = pos, endpos = pos + c, filter = ents.GetAll()}).Hit and !CheckObstruction(ply, pos + c /* 76561198398853124 */)) then
pos = pos + c
break
end
end
end
end
ply.SH_PositionBeforeTeleport = ply:GetPos()
ply:SetPos(pos)
end
function SH_REPORTS:FindReport(id)
return self.ActiveReports[id]
end
function SH_REPORTS:GetAllReports(author)
local t = {}
for id, report in pairs (self.ActiveReports) do
if (author and report.reporter_id ~= author) then
continue end
t[id] = report
end
return t
end
function SH_REPORTS:Log(s)
if (!self.UseServerLog) then
return end
ServerLog(s .. "\n")
end
local function GetPerformanceReport(date, preps)
for id, ps in pairs (preps) do
if (date >= ps[1] and date <= ps[2]) then
return id
end
end
end
function SH_REPORTS:RebuildPerformance()
local preps = {}
self:BetterQuery("SELECT * FROM sh_reports_performance_reports", {}, function(q, ok, data)
for k, v in pairs (data) do
preps[tonumber(v.id)] = {tonumber(v.start_time), tonumber(v.end_time)}
end
self:BetterQuery("SELECT * FROM sh_reports_performance_history", {}, function(q, ok, data)
local staffreps = {}
for _, rep in SortedPairsByMemberValue (data, "date") do
local admin = tostring(rep.admin)
staffreps[admin] = staffreps[admin] or {}
table.insert(staffreps[admin], rep)
end
local staffpreps = {}
for sid, reps in pairs (staffreps) do
staffpreps[sid] = {}
for _, rep in pairs (reps) do
local prepid = GetPerformanceReport(tonumber(rep.date), preps)
staffpreps[sid][prepid] = staffpreps[sid][prepid] or {}
table.insert(staffpreps[sid][prepid], rep)
end
end
for sid, preps in pairs (staffpreps) do
for prepid, reps in pairs (preps) do
local claimed, closed, timespent = 0, 0, 0
for _, rep in pairs (reps) do
claimed = claimed + 1
closed = closed + 1
timespent = timespent + tonumber(rep.waiting_time)
end
self:BetterQuery("SELECT * FROM sh_reports_performance WHERE steamid = {steamid} AND report_id = {prepid}", {steamid = sid, prepid = prepid}, function(q, ok, data)
if (data and data[1]) then
self:BetterQuery("UPDATE sh_reports_performance SET claimed = {claimed}, closed = {closed}, timespent = {timespent} WHERE steamid = {steamid} AND report_id = {prepid}", {claimed = claimed, closed = closed, timespent = timespent, steamid = sid, prepid = prepid})
else
self:BetterQuery("INSERT INTO sh_reports_performance (steamid, claimed, closed, timespent, report_id) VALUES ({steamid}, {claimed}, {closed}, {timespent}, {prepid})", {claimed = claimed, closed = closed, timespent = timespent, steamid = sid, prepid = prepid})
end
end)
end
end
end)
end)
end
hook.Add("PlayerDisconnected", "SH_REPORTS.PlayerDisconnected", function(ply)
SH_REPORTS:PlayerDisconnected(ply)
end)
hook.Add("PlayerSay", "SH_REPORTS.PlayerSay", function(ply, str)
local r = SH_REPORTS:PlayerSay(ply, str)
if (r) then
return r
end
end)
hook.Add("DoPlayerDeath", "SH_REPORTS.DoPlayerDeath", function(ply, atk, dmginfo)
if (IsValid(atk) and atk:IsPlayer() and atk ~= ply) then
ply.SH_LastKiller = atk
end
end)
hook.Add("playerArrested", "SH_REPORTS.playerArrested", function(ply, time, arrester)
if (IsValid(arrester) and arrester:IsPlayer() and arrester ~= ply) then
ply.SH_LastArrester = arrester
end
end)
hook.Add("PlayerButtonDown", "SH_REPORTS.PlayerButtonDown", function(ply, btn)
if (!IsFirstTimePredicted()) then
return end
if (btn == SH_REPORTS.ReportKey) then
if (!SH_REPORTS:IsAdmin(ply) or SH_REPORTS.StaffCanReport) then
easynet.Send(ply, "SH_REPORTS.QuickReport", {comment = "", lastkiller = ply.SH_LastKiller, lastarrester = ply.SH_LastArrester})
else
SH_REPORTS:Notify(ply, "cannot_report_as_admin", false)
end
elseif (btn == SH_REPORTS.ReportsKey) then
SH_REPORTS:ShowReports(ply)
end
end)
timer.Create("SH_REPORTS.MidnightCheck", 1, 0, function()
SH_REPORTS:MidnightCheck()
end)
easynet.Callback("SH_REPORTS.NewReport", function(data, ply)
local report = data
data.reporter_name = ply:Nick()
data.reporter_id = ply:SteamID64()
data.time = os.time()
data.admin_id = ""
data.comment = data.comment:sub(1, SH_REPORTS.MaxCommentLength)
data.is_admin = SH_REPORTS:IsAdmin(ply)
SH_REPORTS:NewReport(ply, data)
end)
easynet.Callback("SH_REPORTS.Claim", function(data, ply)
if (!SH_REPORTS:IsAdmin(ply)) then
SH_REPORTS:Notify(ply, "not_allowed_to_run_cmd", false)
return
end
local report = SH_REPORTS:FindReport(data.id)
if (!report) then
SH_REPORTS:Notify(ply, "report_non_existent", false)
return
end
SH_REPORTS:ClaimReport(ply, report)
end)
easynet.Callback("SH_REPORTS.ClaimAndTeleport", function(data, ply)
SH_REPORTS:ClaimAndTeleport(ply, data.id, data.bring, data.bring_reported)
end)
easynet.Callback("SH_REPORTS.ClaimAndCSit", function(data, ply)
SH_REPORTS:ClaimAndCSit(ply, data.id)
end)
easynet.Callback("SH_REPORTS.CloseReport", function(data, ply)
SH_REPORTS:CloseReport(ply, data.id)
end)
easynet.Callback("SH_REPORTS.RequestPerfReports", function(data, ply)
SH_REPORTS:ShowPerformanceReports(ply)
end)
easynet.Callback("SH_REPORTS.RequestPerfReportStaff", function(data, ply)
SH_REPORTS:RequestPerfReportStaff(ply, data.id)
end)
easynet.Callback("SH_REPORTS.PlayerReady", function(data, ply)
SH_REPORTS:PlayerReady(ply)
end)
easynet.Callback("SH_REPORTS.RateAdmin", function(data, ply)
SH_REPORTS:RateAdmin(ply, data.report_id, data.rating)
end)
easynet.Callback("SH_REPORTS.RequestStaffRatings", function(data, ply)
SH_REPORTS:RequestStaffRatings(ply)
end)
easynet.Callback("SH_REPORTS.RequestReportHistory", function(data, ply)
SH_REPORTS:RequestReportHistory(ply)
end)
-- vk.com/urbanichka