add sborka
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
AddCSLuaFile("shared.lua")
|
||||
include("shared.lua")
|
||||
|
||||
-- Регистрация всех сетевых сообщений
|
||||
util.AddNetworkString("SchoolBoard_OpenMenu")
|
||||
util.AddNetworkString("SchoolBoard_SaveLayout")
|
||||
util.AddNetworkString("SchoolBoard_SyncLayout")
|
||||
util.AddNetworkString("SchoolBoard_RequestLayout")
|
||||
util.AddNetworkString("SchoolBoard_Clear_Req")
|
||||
util.AddNetworkString("SchoolBoard_Clear_Do")
|
||||
util.AddNetworkString("SchoolBoard_DrawLine")
|
||||
util.AddNetworkString("SchoolBoard_SavePosition")
|
||||
util.AddNetworkString("SchoolBoard_SyncPosition")
|
||||
util.AddNetworkString("SchoolBoard_SaveRotation")
|
||||
util.AddNetworkString("SchoolBoard_SyncRotation")
|
||||
|
||||
|
||||
-- helper: only SAM ranks superadmin/curator (or equivalent usergroups) can modify board
|
||||
local function CanModifyBoard(ply)
|
||||
if not IsValid(ply) or not ply:IsPlayer() then return false end
|
||||
|
||||
-- standard checks
|
||||
if ply:IsSuperAdmin() then return true end
|
||||
if ply:GetUserGroup() == "curator" then return true end
|
||||
|
||||
-- if SAM is present, consult its API as a fallback
|
||||
if sam and sam.IsPlayerInRank then
|
||||
if sam.IsPlayerInRank(ply, "superadmin") or sam.IsPlayerInRank(ply, "curator") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- append log entries to a file and console
|
||||
local function LogBoardChange(ply, ent, action)
|
||||
local name = IsValid(ply) and ply:Nick() or "Console"
|
||||
local sid = IsValid(ply) and ply:SteamID() or "N/A"
|
||||
local id = IsValid(ent) and ent:EntIndex() or 0
|
||||
local pos = IsValid(ent) and tostring(ent:GetPos()) or "unknown"
|
||||
local msg = string.format("[%s] %s (%s) %s board #%d at %s\n", os.date(), name, sid, action, id, pos)
|
||||
|
||||
print(msg)
|
||||
file.Append("schoolboard_changes.txt", msg)
|
||||
end
|
||||
|
||||
-- console command for printing current log (admins only)
|
||||
concommand.Add("schoolboard_printlog", function(ply, cmd, args)
|
||||
if IsValid(ply) and not CanModifyBoard(ply) then
|
||||
ply:ChatPrint("Нет доступа к логу доски.")
|
||||
return
|
||||
end
|
||||
|
||||
local contents = file.Read("schoolboard_changes.txt", "DATA") or ""
|
||||
if IsValid(ply) then
|
||||
ply:PrintMessage(HUD_PRINTCONSOLE, contents)
|
||||
ply:ChatPrint("Лог выведен в консоль.")
|
||||
else
|
||||
print(contents)
|
||||
end
|
||||
end)
|
||||
|
||||
-- очистка лога доски (только для старшего админства)
|
||||
concommand.Add("schoolboard_clearlog", function(ply, cmd, args)
|
||||
if IsValid(ply) and not CanModifyBoard(ply) then
|
||||
ply:ChatPrint("Нет доступа к управлению логом.")
|
||||
return
|
||||
end
|
||||
|
||||
file.Write("schoolboard_changes.txt", "")
|
||||
if IsValid(ply) then
|
||||
ply:ChatPrint("Лог доски очищен.")
|
||||
ply:PrintMessage(HUD_PRINTCONSOLE, "Лог доски был очищен.")
|
||||
else
|
||||
print("schoolboard_changes.txt was cleared by console")
|
||||
end
|
||||
end)
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/props/cs_office/offcorkboarda.mdl")
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:SetUseType(SIMPLE_USE) -- Позволяет нажимать 'E' на доску
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
self.BoardLayoutStr = "[]" -- По умолчанию пустой массив JSON
|
||||
self.PositionOffset = Vector(3713.2, 4595.6, -200) -- Смещение позиции доски в 3D пространстве
|
||||
self.RotationOffset = Angle(0, -180, 90) -- Смещение поворота доски
|
||||
end
|
||||
|
||||
-- Открываем меню настройки, когда игрок нажимает 'E'
|
||||
function ENT:Use(activator, caller)
|
||||
if IsValid(activator) and activator:IsPlayer() then
|
||||
if not CanModifyBoard(activator) then
|
||||
activator:ChatPrint("Только superadmin/curator может редактировать доску.")
|
||||
return
|
||||
end
|
||||
|
||||
net.Start("SchoolBoard_OpenMenu")
|
||||
net.WriteEntity(self)
|
||||
net.Send(activator)
|
||||
end
|
||||
end
|
||||
|
||||
-- Клиент отправляет свой новый макет доски (массив картинок и текстов)
|
||||
net.Receive("SchoolBoard_SaveLayout", function(len, ply)
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if len > 64000 then -- Ограничение размера пакета на всякий случай
|
||||
return
|
||||
end
|
||||
|
||||
local layoutSize = net.ReadUInt(32)
|
||||
local compressedData = net.ReadData(layoutSize)
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "school_board" then
|
||||
-- Разрешены только superadmin/curator (SAM ранги) или соответствующие usergroup
|
||||
if not CanModifyBoard(ply) then
|
||||
if IsValid(ply) then ply:ChatPrint("У вас нет прав для изменения доски.") end
|
||||
return
|
||||
end
|
||||
|
||||
-- Проверка расстояния, чтобы школьник с другого конца карты не менял доску
|
||||
if ply:GetPos():DistToSqr(ent:GetPos()) > 500000 then return end
|
||||
|
||||
ent.BoardLayoutStr = util.Decompress(compressedData) or "[]"
|
||||
|
||||
-- логируем факт сохранения
|
||||
LogBoardChange(ply, ent, "saved layout")
|
||||
|
||||
-- Рассказываем всем остальным, что доска обновилась
|
||||
net.Start("SchoolBoard_SyncLayout")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteUInt(layoutSize, 32)
|
||||
net.WriteData(compressedData, layoutSize)
|
||||
net.Broadcast()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Когда игрок подключается или загружает сущность, он просит её данные
|
||||
net.Receive("SchoolBoard_RequestLayout", function(len, ply)
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "school_board" then
|
||||
if not ent.BoardLayoutStr then ent.BoardLayoutStr = "[]" end
|
||||
|
||||
local compressedData = util.Compress(ent.BoardLayoutStr)
|
||||
if compressedData then
|
||||
local layoutSize = string.len(compressedData)
|
||||
|
||||
net.Start("SchoolBoard_SyncLayout")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteUInt(layoutSize, 32)
|
||||
net.WriteData(compressedData, layoutSize)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Принимаем запрос на очистку от игрока и рассылаем всем
|
||||
net.Receive("SchoolBoard_Clear_Req", function(len, ply)
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "school_board" then
|
||||
if not CanModifyBoard(ply) then
|
||||
if IsValid(ply) then ply:ChatPrint("У вас нет прав для изменения доски.") end
|
||||
return
|
||||
end
|
||||
|
||||
LogBoardChange(ply, ent, "cleared board")
|
||||
|
||||
net.Start("SchoolBoard_Clear_Do")
|
||||
net.WriteEntity(ent)
|
||||
net.Broadcast()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Принимаем координаты линии и цвет от рисующего и рассылаем остальным
|
||||
net.Receive("SchoolBoard_DrawLine", function(len, ply)
|
||||
local ent = net.ReadEntity()
|
||||
local x1 = net.ReadFloat()
|
||||
local y1 = net.ReadFloat()
|
||||
local x2 = net.ReadFloat()
|
||||
local y2 = net.ReadFloat()
|
||||
local r = net.ReadUInt(8)
|
||||
local g = net.ReadUInt(8)
|
||||
local b = net.ReadUInt(8)
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "school_board" then
|
||||
-- ограничения на рисование маркером
|
||||
if not CanModifyBoard(ply) then return end
|
||||
|
||||
-- Проверяем, что игрок стоит рядом с доской
|
||||
if ply:GetPos():DistToSqr(ent:GetPos()) > 50000 then return end
|
||||
|
||||
net.Start("SchoolBoard_DrawLine", true) -- unreliable пакет
|
||||
net.WriteEntity(ent)
|
||||
net.WriteFloat(x1)
|
||||
net.WriteFloat(y1)
|
||||
net.WriteFloat(x2)
|
||||
net.WriteFloat(y2)
|
||||
net.WriteUInt(r, 8)
|
||||
net.WriteUInt(g, 8)
|
||||
net.WriteUInt(b, 8)
|
||||
net.SendOmit(ply) -- Отправляем всем, кроме рисующего
|
||||
end
|
||||
end)
|
||||
|
||||
-- Сохраняем позицию доски (смещение вектора)
|
||||
net.Receive("SchoolBoard_SavePosition", function(len, ply)
|
||||
local ent = net.ReadEntity()
|
||||
local offsetX = net.ReadFloat()
|
||||
local offsetY = net.ReadFloat()
|
||||
local offsetZ = net.ReadFloat()
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "school_board" then
|
||||
if not CanModifyBoard(ply) then
|
||||
if IsValid(ply) then ply:ChatPrint("У вас нет прав для изменения доски.") end
|
||||
return
|
||||
end
|
||||
-- Проверка расстояния
|
||||
if ply:GetPos():DistToSqr(ent:GetPos()) > 500000 then return end
|
||||
|
||||
ent.PositionOffset = Vector(offsetX, offsetY, offsetZ)
|
||||
|
||||
-- логируем изменение позиции
|
||||
LogBoardChange(ply, ent, "changed position")
|
||||
|
||||
-- Синхронизируем позицию со всеми
|
||||
net.Start("SchoolBoard_SyncPosition")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteFloat(offsetX)
|
||||
net.WriteFloat(offsetY)
|
||||
net.WriteFloat(offsetZ)
|
||||
net.Broadcast()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Сохраняем поворот доски (смещение угла)
|
||||
net.Receive("SchoolBoard_SaveRotation", function(len, ply)
|
||||
local ent = net.ReadEntity()
|
||||
local pitch = net.ReadFloat()
|
||||
local yaw = net.ReadFloat()
|
||||
local roll = net.ReadFloat()
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "school_board" then
|
||||
if not CanModifyBoard(ply) then
|
||||
if IsValid(ply) then ply:ChatPrint("У вас нет прав для изменения доски.") end
|
||||
return
|
||||
end
|
||||
-- Проверка расстояния
|
||||
if ply:GetPos():DistToSqr(ent:GetPos()) > 500000 then return end
|
||||
|
||||
ent.RotationOffset = Angle(pitch, yaw, roll)
|
||||
|
||||
-- логируем изменение поворота
|
||||
LogBoardChange(ply, ent, "changed rotation")
|
||||
|
||||
-- Синхронизируем поворот со всеми
|
||||
net.Start("SchoolBoard_SyncRotation")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteFloat(pitch)
|
||||
net.WriteFloat(yaw)
|
||||
net.WriteFloat(roll)
|
||||
net.Broadcast()
|
||||
end
|
||||
end)
|
||||
Reference in New Issue
Block a user