add sborka
This commit is contained in:
1879
garrysmod/addons/shkaf/lua/entities/wardrobe_ent/cl_init.lua
Normal file
1879
garrysmod/addons/shkaf/lua/entities/wardrobe_ent/cl_init.lua
Normal file
File diff suppressed because it is too large
Load Diff
351
garrysmod/addons/shkaf/lua/entities/wardrobe_ent/init.lua
Normal file
351
garrysmod/addons/shkaf/lua/entities/wardrobe_ent/init.lua
Normal file
@@ -0,0 +1,351 @@
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
AddCSLuaFile("shared.lua")
|
||||
include("shared.lua")
|
||||
|
||||
resource.AddFile("materials/wardrobe_ui/body.png")
|
||||
resource.AddFile("materials/wardrobe_ui/fon.png")
|
||||
|
||||
util.AddNetworkString("SandboxWardrobeOpen")
|
||||
util.AddNetworkString("SandboxWardrobeApply")
|
||||
util.AddNetworkString("SandboxWardrobeAdminOpen")
|
||||
util.AddNetworkString("SandboxWardrobeAdminUpdate")
|
||||
util.AddNetworkString("SandboxWardrobeCommanderOpen")
|
||||
util.AddNetworkString("SandboxWardrobeCommanderApply")
|
||||
util.AddNetworkString("SandboxWardrobeSavePreset")
|
||||
|
||||
if not file.Exists("wardrobe_presets", "DATA") then
|
||||
file.CreateDir("wardrobe_presets")
|
||||
end
|
||||
|
||||
net.Receive("SandboxWardrobeSavePreset", function(len, ply)
|
||||
if not IsValid(ply) then return end
|
||||
local presets = net.ReadTable()
|
||||
local steamID64 = ply:SteamID64()
|
||||
if steamID64 then
|
||||
local json = util.TableToJSON(presets, true)
|
||||
if json then
|
||||
file.Write("wardrobe_presets/" .. steamID64 .. ".txt", json)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- =====================================================================
|
||||
-- ПСЕВДО-ФУНКЦИИ: Замените на свои реальные проверки!
|
||||
-- =====================================================================
|
||||
|
||||
-- Проверяет, является ли игрок командиром подразделения.
|
||||
-- Замените тело функции на свою логику, например:
|
||||
-- return ply:GetNWBool("IsSquadLeader", false)
|
||||
-- return ply:Team() == TEAM_COMMANDER
|
||||
-- return ply.isCommander == true
|
||||
local function IsCommander(ply)
|
||||
-- ЗАГЛУШКА: Сейчас возвращает true для суперадминов.
|
||||
-- Замените на реальную проверку!
|
||||
return IsValid(ply) and ply:IsSuperAdmin()
|
||||
end
|
||||
|
||||
-- Возвращает таблицу игроков, которые находятся в подразделении этого командира.
|
||||
-- Замените тело функции на свою логику, например:
|
||||
-- return GetSquadByLeader(ply)
|
||||
-- return team.GetPlayers(ply:Team())
|
||||
-- return ply:GetSquadMembers()
|
||||
local function GetSquadMembers(commander)
|
||||
-- ЗАГЛУШКА: Сейчас возвращает всех игроков на сервере кроме самого командира.
|
||||
-- Замените на реальную логику получения списка подразделения!
|
||||
local members = {}
|
||||
for _, ply in ipairs(player.GetAll()) do
|
||||
if ply ~= commander then
|
||||
table.insert(members, ply)
|
||||
end
|
||||
end
|
||||
return members
|
||||
end
|
||||
|
||||
-- =====================================================================
|
||||
-- СИСТЕМА РАЗБЛОКИРОВКИ БОДИГРУПП (АДМИН)
|
||||
-- =====================================================================
|
||||
|
||||
local function SanitizeData(tbl, depth)
|
||||
depth = depth or 1
|
||||
local out = {}
|
||||
for k, v in pairs(tbl) do
|
||||
local keyStr = tostring(k)
|
||||
if depth == 1 then
|
||||
if type(k) == "number" and k > 1e15 then continue end
|
||||
if type(k) == "string" and string.find(keyStr, "e%+") then continue end
|
||||
end
|
||||
if type(v) == "table" then
|
||||
out[keyStr] = SanitizeData(v, depth + 1)
|
||||
else
|
||||
out[keyStr] = v
|
||||
end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function LoadWardrobeUnlocked()
|
||||
if file.Exists("wardrobe_unlocked.txt", "DATA") then
|
||||
local content = file.Read("wardrobe_unlocked.txt", "DATA")
|
||||
local parsed = util.JSONToTable(content, true, true)
|
||||
if parsed then
|
||||
WARDROBE_UNLOCKED = SanitizeData(parsed)
|
||||
else
|
||||
WARDROBE_UNLOCKED = {}
|
||||
end
|
||||
else
|
||||
WARDROBE_UNLOCKED = {}
|
||||
end
|
||||
end
|
||||
LoadWardrobeUnlocked()
|
||||
|
||||
function SaveWardrobeUnlocked()
|
||||
local json = util.TableToJSON(WARDROBE_UNLOCKED, true)
|
||||
if json then
|
||||
file.Write("wardrobe_unlocked.txt", json)
|
||||
end
|
||||
end
|
||||
|
||||
-- =====================================================================
|
||||
-- АДМИН ПАНЕЛЬ
|
||||
-- =====================================================================
|
||||
|
||||
concommand.Add("wardrobe_admin", function(ply, cmd, args)
|
||||
if IsValid(ply) and not ply:IsSuperAdmin() then
|
||||
ply:ChatPrint("У вас нет прав (нужна группа superadmin).")
|
||||
return
|
||||
end
|
||||
net.Start("SandboxWardrobeAdminOpen")
|
||||
net.WriteTable(WARDROBE_UNLOCKED)
|
||||
net.Send(ply)
|
||||
end)
|
||||
|
||||
net.Receive("SandboxWardrobeAdminUpdate", function(len, ply)
|
||||
if not IsValid(ply) or not ply:IsSuperAdmin() then return end
|
||||
|
||||
local sid64 = net.ReadString()
|
||||
local model = string.lower(net.ReadString())
|
||||
local bg_id = tostring(net.ReadUInt(8))
|
||||
local bg_val = tostring(net.ReadUInt(8))
|
||||
local state = net.ReadBool()
|
||||
|
||||
WARDROBE_UNLOCKED[sid64] = WARDROBE_UNLOCKED[sid64] or {}
|
||||
WARDROBE_UNLOCKED[sid64][model] = WARDROBE_UNLOCKED[sid64][model] or {}
|
||||
WARDROBE_UNLOCKED[sid64][model][bg_id] = WARDROBE_UNLOCKED[sid64][model][bg_id] or {}
|
||||
|
||||
if state then
|
||||
WARDROBE_UNLOCKED[sid64][model][bg_id][bg_val] = true
|
||||
else
|
||||
WARDROBE_UNLOCKED[sid64][model][bg_id][bg_val] = nil
|
||||
if table.IsEmpty(WARDROBE_UNLOCKED[sid64][model][bg_id]) then WARDROBE_UNLOCKED[sid64][model][bg_id] = nil end
|
||||
if table.IsEmpty(WARDROBE_UNLOCKED[sid64][model]) then WARDROBE_UNLOCKED[sid64][model] = nil end
|
||||
if table.IsEmpty(WARDROBE_UNLOCKED[sid64]) then WARDROBE_UNLOCKED[sid64] = nil end
|
||||
end
|
||||
|
||||
SaveWardrobeUnlocked()
|
||||
end)
|
||||
|
||||
-- =====================================================================
|
||||
-- ПАНЕЛЬ КОМАНДИРА
|
||||
-- =====================================================================
|
||||
|
||||
concommand.Add("wardrobe_commander", function(ply, cmd, args)
|
||||
if not IsValid(ply) then return end
|
||||
if not IsCommander(ply) then
|
||||
ply:ChatPrint("Вы не являетесь командиром подразделения.")
|
||||
return
|
||||
end
|
||||
|
||||
local members = GetSquadMembers(ply)
|
||||
local membersData = {}
|
||||
for _, member in ipairs(members) do
|
||||
if IsValid(member) then
|
||||
table.insert(membersData, {
|
||||
nick = member:Nick(),
|
||||
sid64 = member:SteamID64(),
|
||||
model = member:GetModel(),
|
||||
entIndex = member:EntIndex(),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
net.Start("SandboxWardrobeCommanderOpen")
|
||||
net.WriteTable(membersData)
|
||||
net.Send(ply)
|
||||
end)
|
||||
|
||||
net.Receive("SandboxWardrobeCommanderApply", function(len, ply)
|
||||
if not IsValid(ply) then return end
|
||||
if not IsCommander(ply) then return end
|
||||
|
||||
local targetEntIndex = net.ReadUInt(16)
|
||||
local isWipe = net.ReadBool()
|
||||
|
||||
local target = Entity(targetEntIndex)
|
||||
if not IsValid(target) or not target:IsPlayer() then
|
||||
ply:ChatPrint("Целевой игрок не найден.")
|
||||
return
|
||||
end
|
||||
|
||||
-- Проверяем что целевой игрок находится в подразделении командира
|
||||
local members = GetSquadMembers(ply)
|
||||
local isMember = false
|
||||
for _, member in ipairs(members) do
|
||||
if member == target then
|
||||
isMember = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not isMember then
|
||||
ply:ChatPrint("Этот игрок не в вашем подразделении.")
|
||||
return
|
||||
end
|
||||
|
||||
if isWipe then
|
||||
target:SetSkin(0)
|
||||
local bgs = target:GetBodyGroups()
|
||||
for _, bg in ipairs(bgs) do
|
||||
target:SetBodygroup(bg.id, 0)
|
||||
end
|
||||
ply:ChatPrint("Сброшена экипировка для: " .. target:Nick())
|
||||
return
|
||||
end
|
||||
|
||||
local bodygroups = net.ReadTable()
|
||||
local skin = net.ReadUInt(8)
|
||||
|
||||
for idx, value in pairs(bodygroups) do
|
||||
target:SetBodygroup(idx, value)
|
||||
end
|
||||
target:SetSkin(skin)
|
||||
|
||||
ply:ChatPrint("Экипировка применена для: " .. target:Nick())
|
||||
end)
|
||||
|
||||
-- =====================================================================
|
||||
-- ЛОГИКА ЭНТИТИ ГАРДЕРОБА
|
||||
-- =====================================================================
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/props_wasteland/controlroom_storagecloset001a.mdl")
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then phys:Wake() end
|
||||
|
||||
self.playerCooldowns = {}
|
||||
end
|
||||
|
||||
function ENT:GetModelBodygroups(model)
|
||||
local tempEnt = ents.Create("prop_dynamic")
|
||||
if not IsValid(tempEnt) then return {} end
|
||||
tempEnt:SetModel(model)
|
||||
tempEnt:Spawn()
|
||||
|
||||
local bodygroups = {}
|
||||
for i = 0, tempEnt:GetNumBodyGroups() - 1 do
|
||||
local name = tempEnt:GetBodygroupName(i)
|
||||
local count = tempEnt:GetBodygroupCount(i)
|
||||
if count > 1 then
|
||||
bodygroups[i] = {name = name, count = count, index = i}
|
||||
end
|
||||
end
|
||||
|
||||
tempEnt:Remove()
|
||||
return bodygroups
|
||||
end
|
||||
|
||||
function ENT:GetModelSkinCount(model)
|
||||
local tempEnt = ents.Create("prop_dynamic")
|
||||
if not IsValid(tempEnt) then return 0 end
|
||||
tempEnt:SetModel(model)
|
||||
tempEnt:Spawn()
|
||||
|
||||
local skinCount = tempEnt:SkinCount() or 0
|
||||
tempEnt:Remove()
|
||||
return skinCount
|
||||
end
|
||||
|
||||
function ENT:Use(activator)
|
||||
if not IsValid(activator) or not activator:IsPlayer() then return end
|
||||
|
||||
local steamID = activator:SteamID()
|
||||
local now = CurTime()
|
||||
if self.playerCooldowns[steamID] and (now - self.playerCooldowns[steamID]) < 2 then return end
|
||||
|
||||
local model = activator:GetModel()
|
||||
if not model then return end
|
||||
|
||||
local bodygroups = self:GetModelBodygroups(model)
|
||||
local skinCount = self:GetModelSkinCount(model)
|
||||
|
||||
local availableBodygroups = {}
|
||||
for idx, data in pairs(bodygroups) do
|
||||
availableBodygroups[idx] = data
|
||||
end
|
||||
|
||||
local availableSkins = {}
|
||||
for i = 0, skinCount - 1 do
|
||||
table.insert(availableSkins, i)
|
||||
end
|
||||
|
||||
local currentBodygroups = {}
|
||||
for idx in pairs(availableBodygroups) do
|
||||
currentBodygroups[idx] = activator:GetBodygroup(idx)
|
||||
end
|
||||
|
||||
local currentSkin = activator:GetSkin()
|
||||
|
||||
local steamID64 = activator:SteamID64()
|
||||
local unlocked = {}
|
||||
if steamID64 and WARDROBE_UNLOCKED[steamID64] and WARDROBE_UNLOCKED[steamID64][string.lower(model)] then
|
||||
unlocked = WARDROBE_UNLOCKED[steamID64][string.lower(model)]
|
||||
end
|
||||
|
||||
local presets = {}
|
||||
if steamID64 and file.Exists("wardrobe_presets/" .. steamID64 .. ".txt", "DATA") then
|
||||
local content = file.Read("wardrobe_presets/" .. steamID64 .. ".txt", "DATA")
|
||||
if content and content ~= "" then
|
||||
presets = util.JSONToTable(content) or {}
|
||||
end
|
||||
end
|
||||
|
||||
self.playerCooldowns[steamID] = now
|
||||
|
||||
net.Start("SandboxWardrobeOpen")
|
||||
net.WriteString(model)
|
||||
net.WriteTable(availableBodygroups)
|
||||
net.WriteTable(availableSkins)
|
||||
net.WriteTable(currentBodygroups)
|
||||
net.WriteUInt(currentSkin, 8)
|
||||
net.WriteTable(unlocked)
|
||||
net.WriteTable(presets)
|
||||
net.Send(activator)
|
||||
end
|
||||
|
||||
net.Receive("SandboxWardrobeApply", function(len, client)
|
||||
if not IsValid(client) then return end
|
||||
|
||||
local isWipe = net.ReadBool()
|
||||
|
||||
if isWipe then
|
||||
client:SetSkin(0)
|
||||
local bgs = client:GetBodyGroups()
|
||||
for _, bg in ipairs(bgs) do
|
||||
client:SetBodygroup(bg.id, 0)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local bodygroups = net.ReadTable()
|
||||
local skin = net.ReadUInt(8)
|
||||
|
||||
for idx, value in pairs(bodygroups) do
|
||||
client:SetBodygroup(idx, value)
|
||||
end
|
||||
|
||||
client:SetSkin(skin)
|
||||
end)
|
||||
30
garrysmod/addons/shkaf/lua/entities/wardrobe_ent/shared.lua
Normal file
30
garrysmod/addons/shkaf/lua/entities/wardrobe_ent/shared.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_gmodentity"
|
||||
ENT.PrintName = "Гардероб"
|
||||
ENT.Author = "Server"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
ENT.Category = "Sandbox Арсенал"
|
||||
|
||||
-- === НАСТРОЙКИ БЛОКИРОВКИ БОДИГРУПП ===
|
||||
-- Формат: ["путь/к/модели.mdl"] = { {id_бодигруппа, id_вариант, function(ply) return true end, "Название для админ панели"}, ... }
|
||||
-- Внимание: путь к модели должен быть в нижнем регистре.
|
||||
-- Если у бодигруппы указана функция, то она станет доступна, когда функция вернет true. Если функции нет — заблокирована для всех.
|
||||
WARDROBE_BLOCKED_BGS = {
|
||||
["models/cwz/characters/mason_pm.mdl"] = {
|
||||
{2, 1, function(ply) return false end, "Шлем (Вариант 1)"}, -- Пример: блокируем вариант 1 у бодигруппы 2
|
||||
},
|
||||
}
|
||||
|
||||
-- =====================================================================
|
||||
-- ПСЕВДО-ФУНКЦИЯ: Является ли игрок командиром (для клиентской стороны).
|
||||
-- Используется для показа кнопки "КОМАНДИР" в интерфейсе гардероба.
|
||||
-- Замените тело функции на свою проверку, например:
|
||||
-- return ply:GetNWBool("IsSquadLeader", false)
|
||||
-- return ply:Team() == TEAM_COMMANDER
|
||||
-- =====================================================================
|
||||
function IsWardrobeCommander(ply)
|
||||
-- ЗАГЛУШКА: Сейчас возвращает true для суперадминов.
|
||||
-- Замените на реальную проверку!
|
||||
return IsValid(ply) and ply:IsSuperAdmin()
|
||||
end
|
||||
BIN
garrysmod/addons/shkaf/materials/wardrobe_ui/body.png
Normal file
BIN
garrysmod/addons/shkaf/materials/wardrobe_ui/body.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 259 KiB |
BIN
garrysmod/addons/shkaf/materials/wardrobe_ui/fon.jpg
Normal file
BIN
garrysmod/addons/shkaf/materials/wardrobe_ui/fon.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 282 KiB |
BIN
garrysmod/addons/shkaf/sound/door/close.wav
Normal file
BIN
garrysmod/addons/shkaf/sound/door/close.wav
Normal file
Binary file not shown.
BIN
garrysmod/addons/shkaf/sound/door/open.wav
Normal file
BIN
garrysmod/addons/shkaf/sound/door/open.wav
Normal file
Binary file not shown.
Reference in New Issue
Block a user