add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,692 @@
local PLUGIN = PLUGIN
-- Таблица активных отрядов
PLUGIN.squads = PLUGIN.squads or {}
PLUGIN.playerSquads = PLUGIN.playerSquads or {} -- [SteamID] = squadID
PLUGIN.squadInvites = PLUGIN.squadInvites or {} -- [SteamID] = {squadID, inviterSteamID}
util.AddNetworkString("ixSquadCreate")
util.AddNetworkString("ixSquadDisband")
util.AddNetworkString("ixSquadInvite")
util.AddNetworkString("ixSquadAcceptInvite")
util.AddNetworkString("ixSquadDeclineInvite")
util.AddNetworkString("ixSquadKick")
util.AddNetworkString("ixSquadLeave")
util.AddNetworkString("ixSquadPromote")
util.AddNetworkString("ixSquadSync")
util.AddNetworkString("ixSquadNotify")
util.AddNetworkString("ixSquadUpdateMarkers")
util.AddNetworkString("ixSquadPlaceMarker")
util.AddNetworkString("ixSquadWorldMarker")
local function IsAdminMode(ply)
return ply.GetNetVar and ply:GetNetVar("AdminMode", false)
end
-- Генерация уникального ID отряда
function PLUGIN:GenerateSquadID()
local id
repeat
id = "squad_" .. os.time() .. "_" .. math.random(1000, 9999)
until not self.squads[id]
return id
end
-- Получить отряд игрока
function PLUGIN:GetPlayerSquad(client)
local steamID = client:SteamID()
local squadID = self.playerSquads[steamID]
if squadID then
return self.squads[squadID], squadID
end
return nil, nil
end
-- Получить фракцию игрока
function PLUGIN:GetPlayerFaction(client)
local character = client:GetCharacter()
if not character then return nil end
return character:GetFaction()
end
-- Создание отряда
function PLUGIN:CreateSquad(leader)
if IsAdminMode(leader) then
return false, "Администратор не может создавать отряд"
end
if not IsValid(leader) then
return false, "Недействительный игрок"
end
local steamID = leader:SteamID()
-- Проверяем, не состоит ли уже в отряде
if self.playerSquads[steamID] then
return false, "Вы уже состоите в отряде"
end
local faction = self:GetPlayerFaction(leader)
if not faction then
return false, "У вас нет активного персонажа"
end
local squadID = self:GenerateSquadID()
self.squads[squadID] = {
id = squadID,
leader = steamID,
faction = faction,
members = {steamID},
memberData = {
[steamID] = {
name = leader:Name(),
isLeader = true,
joinTime = os.time()
}
},
createdAt = os.time()
}
self.playerSquads[steamID] = squadID
self:SyncSquadToMembers(squadID)
self:StartSquadMarkers(squadID)
-- Логирование создания отряда
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if (serverlogsPlugin) then
local factionName = ix.faction.Get(faction).name or tostring(faction)
local message = string.format("%s создал отряд (ID: %s, фракция: %s)", leader:Nick(), squadID, factionName)
serverlogsPlugin:AddLog("SQUAD_CREATE", message, leader, {
squadID = squadID,
faction = faction,
factionName = factionName
})
end
return true, "Отряд успешно создан"
end
-- Расформирование отряда
function PLUGIN:DisbandSquad(squadID)
local squad = self.squads[squadID]
if not squad then return false, "Отряд не найден" end
-- Логируем расформирование перед удалением
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if (serverlogsPlugin) then
local leaderName = squad.memberData[squad.leader] and squad.memberData[squad.leader].name or "Unknown"
local factionName = ix.faction.Get(squad.faction).name or tostring(squad.faction)
local message = string.format("Отряд %s расформирован (лидер: %s, членов: %d, фракция: %s)",
squadID, leaderName, #squad.members, factionName)
serverlogsPlugin:AddLog("SQUAD_DELETE", message, nil, {
squadID = squadID,
leader = squad.leader,
leaderName = leaderName,
memberCount = #squad.members,
faction = squad.faction,
factionName = factionName
})
end
-- Останавливаем маркеры
self:StopSquadMarkers(squadID)
-- Очищаем данные на клиенте и уведомляем всех членов
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
-- Отправляем пустую таблицу для очистки данных на клиенте
net.Start("ixSquadSync")
net.WriteString("{}")
net.Send(member)
net.Start("ixSquadNotify")
net.WriteString("Отряд был расформирован")
net.Send(member)
end
self.playerSquads[memberSteamID] = nil
end
self.squads[squadID] = nil
return true, "Отряд расформирован"
end
-- Приглашение в отряд
function PLUGIN:InviteToSquad(inviter, target)
print("[SQUADS] InviteToSquad вызван: inviter=" .. (IsValid(inviter) and inviter:Name() or "NIL") .. ", target=" .. (IsValid(target) and target:Name() or "NIL"))
if IsAdminMode(inviter) then
return false, "Администратор не может приглашать в отряд"
end
if not IsValid(inviter) or not IsValid(target) then
print("[SQUADS] Ошибка: недействительный игрок")
return false, "Недействительный игрок"
end
local squad, squadID = self:GetPlayerSquad(inviter)
if not squad then
print("[SQUADS] Ошибка: инвайтер не в отряде")
return false, "Вы не состоите в отряде"
end
print("[SQUADS] Отряд найден: " .. squadID)
local inviterSteamID = inviter:SteamID()
if squad.leader ~= inviterSteamID then
print("[SQUADS] Ошибка: не лидер (leader=" .. squad.leader .. ", inviter=" .. inviterSteamID .. ")")
return false, "Только лидер может приглашать игроков"
end
local targetSteamID = target:SteamID()
-- Проверяем, не состоит ли уже в отряде
if self.playerSquads[targetSteamID] then
print("[SQUADS] Ошибка: target уже в отряде")
return false, target:Name() .. " уже состоит в отряде"
end
-- Проверяем лимит
if #squad.members >= ix.config.Get("squadMaxMembers", 16) then
print("[SQUADS] Ошибка: отряд заполнен")
return false, "Отряд заполнен (макс. " .. ix.config.Get("squadMaxMembers", 16) .. " человек)"
end
-- Проверяем фракцию
local targetFaction = self:GetPlayerFaction(target)
if targetFaction ~= squad.faction then
print("[SQUADS] Ошибка: разные фракции (squad=" .. squad.faction .. ", target=" .. (targetFaction or "NIL") .. ")")
return false, target:Name() .. " из другой фракции"
end
-- Проверяем, нет ли уже приглашения
if self.squadInvites[targetSteamID] then
print("[SQUADS] Ошибка: у target уже есть приглашение")
return false, target:Name() .. " уже имеет активное приглашение"
end
-- Сохраняем приглашение
self.squadInvites[targetSteamID] = {
squadID = squadID,
inviterSteamID = inviterSteamID,
inviterName = inviter:Name(),
time = CurTime()
}
print("[SQUADS] Приглашение сохранено для " .. target:Name())
-- Отправляем приглашение
net.Start("ixSquadInvite")
net.WriteString(squadID)
net.WriteString(inviter:Name())
net.Send(target)
print("[SQUADS] Приглашение отправлено клиенту " .. target:Name())
-- Уведомляем инвайтера
net.Start("ixSquadNotify")
net.WriteString("Приглашение отправлено " .. target:Name())
net.Send(inviter)
-- Логирование приглашения в отряд
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if (serverlogsPlugin) then
local message = string.format("%s пригласил %s в отряд %s", inviter:Nick(), target:Nick(), squadID)
serverlogsPlugin:AddLog("SQUAD_INVITE", message, inviter, {
squadID = squadID,
targetSteamID = targetSteamID,
targetName = target:Nick()
})
end
-- Автоматическое удаление через 30 секунд
timer.Simple(30, function()
if self.squadInvites[targetSteamID] and self.squadInvites[targetSteamID].squadID == squadID then
self.squadInvites[targetSteamID] = nil
print("[SQUADS] Приглашение для " .. targetSteamID .. " истекло")
end
end)
return true, "Приглашение отправлено"
end
-- Принятие приглашения
function PLUGIN:AcceptSquadInvite(client)
local steamID = client:SteamID()
local invite = self.squadInvites[steamID]
if IsAdminMode(client) then
return false, "Администратор не может вступать в отряд"
end
if not invite then
return false, "У вас нет активных приглашений"
end
local squad = self.squads[invite.squadID]
if not squad then
self.squadInvites[steamID] = nil
return false, "Отряд больше не существует"
end
-- Проверяем лимит еще раз
if #squad.members >= ix.config.Get("squadMaxMembers", 16) then
self.squadInvites[steamID] = nil
return false, "Отряд уже заполнен"
end
-- Проверяем фракцию еще раз (на случай смены персонажа)
local currentFaction = self:GetPlayerFaction(client)
if currentFaction ~= squad.faction then
self.squadInvites[steamID] = nil
return false, "Вы больше не в той же фракции"
end
-- Добавляем в отряд
table.insert(squad.members, steamID)
squad.memberData[steamID] = {
name = client:Name(),
isLeader = false,
joinTime = os.time()
}
self.playerSquads[steamID] = invite.squadID
self.squadInvites[steamID] = nil
-- Уведомляем всех членов отряда
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
net.Start("ixSquadNotify")
net.WriteString(client:Name() .. " присоединился к отряду")
net.Send(member)
end
end
self:SyncSquadToMembers(invite.squadID)
-- Логирование вступления в отряд
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if (serverlogsPlugin) then
local factionName = ix.faction.Get(squad.faction).name or tostring(squad.faction)
local message = string.format("%s присоединился к отряду %s (лидер: %s)",
client:Nick(), invite.squadID, squad.memberData[squad.leader].name)
serverlogsPlugin:AddLog("SQUAD_JOIN", message, client, {
squadID = invite.squadID,
inviterSteamID = invite.inviterSteamID,
inviterName = invite.inviterName,
faction = squad.faction,
factionName = factionName
})
end
return true, "Вы присоединились к отряду"
end
-- Исключение из отряда
function PLUGIN:KickFromSquad(kicker, targetSteamID)
if not IsValid(kicker) then return false, "Недействительный игрок" end
local squad, squadID = self:GetPlayerSquad(kicker)
if not squad then
return false, "Вы не состоите в отряде"
end
if squad.leader ~= kicker:SteamID() then
return false, "Только лидер может исключать игроков"
end
if targetSteamID == kicker:SteamID() then
return false, "Используйте расформирование отряда"
end
-- Удаляем из отряда
for i, memberSteamID in ipairs(squad.members) do
if memberSteamID == targetSteamID then
table.remove(squad.members, i)
break
end
end
local targetName = squad.memberData[targetSteamID].name
squad.memberData[targetSteamID] = nil
self.playerSquads[targetSteamID] = nil
-- Уведомляем исключенного игрока и очищаем его данные
local target = player.GetBySteamID(targetSteamID)
if IsValid(target) then
-- Очищаем данные отряда на клиенте
net.Start("ixSquadSync")
net.WriteString("{}")
net.Send(target)
net.Start("ixSquadNotify")
net.WriteString("Вы были исключены из отряда")
net.Send(target)
end
-- Уведомляем остальных
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
net.Start("ixSquadNotify")
net.WriteString(targetName .. " был исключен из отряда")
net.Send(member)
end
end
self:SyncSquadToMembers(squadID)
-- Логирование исключения из отряда
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if (serverlogsPlugin) then
local message = string.format("%s исключил %s из отряда %s", kicker:Nick(), targetName, squadID)
serverlogsPlugin:AddLog("SQUAD_KICK", message, kicker, {
squadID = squadID,
targetSteamID = targetSteamID,
targetName = targetName
})
end
return true, targetName .. " исключен из отряда"
end
-- Выход из отряда
function PLUGIN:LeaveSquad(client)
local squad, squadID = self:GetPlayerSquad(client)
if not squad then
return false, "Вы не состоите в отряде"
end
local steamID = client:SteamID()
-- Если лидер - расформировываем отряд
if squad.leader == steamID then
return self:DisbandSquad(squadID)
end
-- Удаляем из отряда
for i, memberSteamID in ipairs(squad.members) do
if memberSteamID == steamID then
table.remove(squad.members, i)
break
end
end
squad.memberData[steamID] = nil
self.playerSquads[steamID] = nil
-- Уведомляем остальных
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
net.Start("ixSquadNotify")
net.WriteString(client:Name() .. " покинул отряд")
net.Send(member)
end
end
self:SyncSquadToMembers(squadID)
-- Логирование выхода из отряда
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if (serverlogsPlugin) then
local message = string.format("%s покинул отряд %s", client:Nick(), squadID)
serverlogsPlugin:AddLog("SQUAD_LEAVE", message, client, {
squadID = squadID
})
end
return true, "Вы покинули отряд"
end
-- Система маркеров на компасе
function PLUGIN:StartSquadMarkers(squadID)
local timerName = "ixSquadMarkers_" .. squadID
timer.Create(timerName, ix.config.Get("squadMarkerUpdateRate", 0.5), 0, function()
local squad = self.squads[squadID]
if not squad then
timer.Remove(timerName)
return
end
-- Обновляем маркеры для каждого члена отряда
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
-- Получаем других членов отряда
local teammates = {}
for _, otherSteamID in ipairs(squad.members) do
if otherSteamID ~= memberSteamID then
local teammate = player.GetBySteamID(otherSteamID)
if IsValid(teammate) and teammate:Alive() then
table.insert(teammates, teammate)
end
end
end
-- Отправляем позиции союзников этому игроку
if #teammates > 0 then
net.Start("ixSquadUpdateMarkers")
net.WriteUInt(#teammates, 8)
for _, teammate in ipairs(teammates) do
net.WriteVector(teammate:GetPos())
net.WriteString(teammate:Name())
net.WriteEntity(teammate)
end
net.Send(member)
end
end
end
end)
end
function PLUGIN:StopSquadMarkers(squadID)
timer.Remove("ixSquadMarkers_" .. squadID)
end
-- Синхронизация данных отряда
function PLUGIN:SyncSquadToMembers(squadID)
local squad = self.squads[squadID]
if not squad then return end
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
net.Start("ixSquadSync")
net.WriteString(util.TableToJSON(squad))
net.Send(member)
end
end
end
function PLUGIN:SyncAllSquads()
for _, client in ipairs(player.GetAll()) do
local squad, squadID = self:GetPlayerSquad(client)
if squad then
net.Start("ixSquadSync")
net.WriteString(util.TableToJSON(squad))
net.Send(client)
end
end
end
-- Обработка отключения игрока
function PLUGIN:PlayerDisconnected(client)
if not IsValid(client) then return end
local steamID = client:SteamID()
local squad, squadID = self:GetPlayerSquad(client)
if squad then
-- Если это лидер - расформировываем отряд
if squad.leader == steamID then
print("[SQUADS] Лидер " .. client:Name() .. " отключился, расформирование отряда " .. squadID)
self:DisbandSquad(squadID)
else
-- Обычный участник - просто покидает отряд
print("[SQUADS] Игрок " .. client:Name() .. " отключился, удаление из отряда " .. squadID)
-- Удаляем из списка участников
for i, memberSteamID in ipairs(squad.members) do
if memberSteamID == steamID then
table.remove(squad.members, i)
break
end
end
squad.memberData[steamID] = nil
self.playerSquads[steamID] = nil
-- Уведомляем остальных участников
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
net.Start("ixSquadNotify")
net.WriteString(client:Name() .. " покинул отряд (отключение)")
net.Send(member)
end
end
-- Синхронизируем данные с оставшимися участниками
self:SyncSquadToMembers(squadID)
end
end
-- Удаляем приглашения
self.squadInvites[steamID] = nil
end
-- Сетевые обработчики
net.Receive("ixSquadCreate", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then
return
end
if IsAdminMode(client) then return end
local success, message = plugin:CreateSquad(client)
net.Start("ixSquadNotify")
net.WriteString(message)
net.Send(client)
end)
net.Receive("ixSquadDisband", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if IsAdminMode(client) then return end
local squad, squadID = plugin:GetPlayerSquad(client)
if squad and squad.leader == client:SteamID() then
plugin:DisbandSquad(squadID)
end
end)
net.Receive("ixSquadInvite", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if IsAdminMode(client) then return end
local targetSteamID = net.ReadString()
print("[SQUADS SERVER] Получен запрос на приглашение от " .. client:Name() .. " для SteamID: " .. targetSteamID)
local target = player.GetBySteamID(targetSteamID)
print("[SQUADS SERVER] Найден игрок: " .. (IsValid(target) and target:Name() or "NIL"))
if IsValid(target) then
local success, message = plugin:InviteToSquad(client, target)
print("[SQUADS SERVER] Результат приглашения: " .. tostring(success) .. " - " .. message)
net.Start("ixSquadNotify")
net.WriteString(message)
net.Send(client)
else
net.Start("ixSquadNotify")
net.WriteString("Игрок не найден")
net.Send(client)
end
end)
net.Receive("ixSquadAcceptInvite", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if IsAdminMode(client) then return end
local success, message = plugin:AcceptSquadInvite(client)
net.Start("ixSquadNotify")
net.WriteString(message)
net.Send(client)
end)
net.Receive("ixSquadDeclineInvite", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if IsAdminMode(client) then return end
local invite = plugin.squadInvites[client:SteamID()]
-- Уведомляем лидера об отклонении
if invite then
local inviter = player.GetBySteamID(invite.inviterSteamID)
if IsValid(inviter) then
net.Start("ixSquadNotify")
net.WriteString(client:Name() .. " отклонил приглашение")
net.Send(inviter)
end
end
plugin.squadInvites[client:SteamID()] = nil
net.Start("ixSquadNotify")
net.WriteString("Приглашение отклонено")
net.Send(client)
end)
net.Receive("ixSquadKick", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if IsAdminMode(client) then return end
local targetSteamID = net.ReadString()
local success, message = plugin:KickFromSquad(client, targetSteamID)
net.Start("ixSquadNotify")
net.WriteString(message)
net.Send(client)
end)
net.Receive("ixSquadLeave", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if IsAdminMode(client) then return end
local success, message = plugin:LeaveSquad(client)
net.Start("ixSquadNotify")
net.WriteString(message)
net.Send(client)
end)
net.Receive("ixSquadPlaceMarker", function(len, client)
local plugin = ix.plugin.Get("squads")
if not plugin then return end
if not IsValid(client) or not client:Alive() then return end
local squad, squadID = plugin:GetPlayerSquad(client)
if not squad then return end
local pos = net.ReadVector()
if not pos then return end
for _, memberSteamID in ipairs(squad.members) do
local member = player.GetBySteamID(memberSteamID)
if IsValid(member) then
net.Start("ixSquadWorldMarker")
net.WriteVector(pos)
net.WriteString(client:Name())
net.Send(member)
end
end
end)