add sborka
This commit is contained in:
253
garrysmod/gamemodes/militaryrp/plugins/squads/cl_plugin.lua
Normal file
253
garrysmod/gamemodes/militaryrp/plugins/squads/cl_plugin.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
local PLUGIN = PLUGIN
|
||||
PLUGIN.lastMarkerPress = 0
|
||||
-- Клиентские данные
|
||||
PLUGIN.currentSquad = PLUGIN.currentSquad or nil
|
||||
PLUGIN.activeMarkers = PLUGIN.activeMarkers or {}
|
||||
|
||||
-- Получение сетевых данных
|
||||
net.Receive("ixSquadSync", function()
|
||||
local jsonData = net.ReadString()
|
||||
local data = util.JSONToTable(jsonData)
|
||||
|
||||
-- Если пришла пустая таблица - очищаем данные отряда
|
||||
if not data or not data.id then
|
||||
PLUGIN.currentSquad = nil
|
||||
|
||||
-- Очищаем маркеры
|
||||
for _, markerID in ipairs(PLUGIN.activeMarkers) do
|
||||
if Adv_Compass_RemoveMarker then
|
||||
Adv_Compass_RemoveMarker(markerID)
|
||||
end
|
||||
end
|
||||
PLUGIN.activeMarkers = {}
|
||||
else
|
||||
PLUGIN.currentSquad = data
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("ixSquadNotify", function()
|
||||
local message = net.ReadString()
|
||||
LocalPlayer():Notify(message)
|
||||
end)
|
||||
|
||||
net.Receive("ixSquadInvite", function()
|
||||
local squadID = net.ReadString()
|
||||
local inviterName = net.ReadString()
|
||||
|
||||
-- Создаем окно приглашения
|
||||
local frame = vgui.Create("DFrame")
|
||||
frame:SetSize(400, 150)
|
||||
frame:Center()
|
||||
frame:SetTitle("")
|
||||
frame:SetDraggable(false)
|
||||
frame:ShowCloseButton(false)
|
||||
frame:MakePopup()
|
||||
frame.Paint = function(s, w, h)
|
||||
draw.RoundedBox(8, 0, 0, w, h, Color(25, 25, 28))
|
||||
surface.SetDrawColor(Color(1, 67, 29))
|
||||
surface.DrawRect(0, 0, w, 3)
|
||||
end
|
||||
|
||||
local title = vgui.Create("DLabel", frame)
|
||||
title:SetPos(0, 20)
|
||||
title:SetSize(400, 30)
|
||||
title:SetFont("F4Menu_Category")
|
||||
title:SetTextColor(Color(255, 255, 255))
|
||||
title:SetText("Приглашение в отряд")
|
||||
title:SetContentAlignment(5)
|
||||
|
||||
local text = vgui.Create("DLabel", frame)
|
||||
text:SetPos(20, 55)
|
||||
text:SetSize(360, 40)
|
||||
text:SetFont("F4Menu_Item")
|
||||
text:SetTextColor(Color(200, 200, 200))
|
||||
text:SetText(inviterName .. " приглашает вас вступить в отряд")
|
||||
text:SetContentAlignment(5)
|
||||
text:SetWrap(true)
|
||||
|
||||
local acceptBtn = vgui.Create("DButton", frame)
|
||||
acceptBtn:SetPos(20, 105)
|
||||
acceptBtn:SetSize(175, 30)
|
||||
acceptBtn:SetText("Принять")
|
||||
acceptBtn:SetFont("F4Menu_Item")
|
||||
acceptBtn:SetTextColor(Color(255, 255, 255))
|
||||
acceptBtn.Paint = function(s, w, h)
|
||||
draw.RoundedBox(6, 0, 0, w, h, s:IsHovered() and Color(1, 87, 39) or Color(1, 67, 29))
|
||||
end
|
||||
acceptBtn.DoClick = function()
|
||||
net.Start("ixSquadAcceptInvite")
|
||||
net.SendToServer()
|
||||
frame:Close()
|
||||
end
|
||||
|
||||
local declineBtn = vgui.Create("DButton", frame)
|
||||
declineBtn:SetPos(205, 105)
|
||||
declineBtn:SetSize(175, 30)
|
||||
declineBtn:SetText("Отклонить")
|
||||
declineBtn:SetFont("F4Menu_Item")
|
||||
declineBtn:SetTextColor(Color(255, 255, 255))
|
||||
declineBtn.Paint = function(s, w, h)
|
||||
draw.RoundedBox(6, 0, 0, w, h, s:IsHovered() and Color(70, 25, 25) or Color(50, 25, 25))
|
||||
end
|
||||
declineBtn.DoClick = function()
|
||||
net.Start("ixSquadDeclineInvite")
|
||||
net.SendToServer()
|
||||
frame:Close()
|
||||
end
|
||||
|
||||
-- Автоматическое закрытие через 30 секунд
|
||||
timer.Simple(30, function()
|
||||
if IsValid(frame) then
|
||||
frame:Close()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
PLUGIN.worldMarker = nil
|
||||
PLUGIN.nextMarkerTime = 0
|
||||
|
||||
net.Receive("ixSquadWorldMarker", function()
|
||||
local pos = net.ReadVector()
|
||||
local name = net.ReadString()
|
||||
|
||||
PLUGIN.worldMarker = {
|
||||
pos = pos,
|
||||
name = name,
|
||||
expire = CurTime() + 10
|
||||
}
|
||||
end)
|
||||
|
||||
net.Receive("ixSquadUpdateMarkers", function()
|
||||
for _, markerID in ipairs(PLUGIN.activeMarkers) do
|
||||
if Adv_Compass_RemoveMarker then
|
||||
Adv_Compass_RemoveMarker(markerID)
|
||||
end
|
||||
end
|
||||
PLUGIN.activeMarkers = {}
|
||||
|
||||
local count = net.ReadUInt(8)
|
||||
local markerColor = ix.config.Get("squadMarkerColor", Color(0, 255, 0))
|
||||
|
||||
for i = 1, count do
|
||||
local pos = net.ReadVector()
|
||||
local name = net.ReadString()
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if IsValid(ent) and mCompass_AddEntityMarker then
|
||||
-- Используем маркер на сущности для отслеживания движения
|
||||
local markerID = mCompass_AddEntityMarker(
|
||||
LocalPlayer(),
|
||||
ent,
|
||||
{LocalPlayer()},
|
||||
CurTime() + 1, -- 1 секунда (обновляется регулярно)
|
||||
markerColor,
|
||||
"", -- Иконка (пустая, используем стандартную)
|
||||
name
|
||||
)
|
||||
table.insert(PLUGIN.activeMarkers, markerID)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Очистка при закрытии
|
||||
function PLUGIN:ShutDown()
|
||||
for _, markerID in ipairs(self.activeMarkers) do
|
||||
if Adv_Compass_RemoveMarker then
|
||||
Adv_Compass_RemoveMarker(markerID)
|
||||
end
|
||||
end
|
||||
self.activeMarkers = {}
|
||||
end
|
||||
|
||||
-- Вспомогательные функции
|
||||
function PLUGIN:GetCurrentSquad()
|
||||
return self.currentSquad
|
||||
end
|
||||
|
||||
function PLUGIN:IsInSquad()
|
||||
return self.currentSquad ~= nil
|
||||
end
|
||||
|
||||
function PLUGIN:IsSquadLeader()
|
||||
if not self.currentSquad then return false end
|
||||
return self.currentSquad.leader == LocalPlayer():SteamID()
|
||||
end
|
||||
|
||||
PLUGIN.wasGPressed = false
|
||||
PLUGIN.nextMarkerTime = 0
|
||||
|
||||
hook.Add("Think", "ixSquadPlaceMarkerKey", function()
|
||||
local ply = LocalPlayer()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if vgui.CursorVisible() then return end
|
||||
if gui.IsGameUIVisible() then return end
|
||||
if ix and ix.gui and ix.gui.menu and IsValid(ix.gui.menu) then return end
|
||||
|
||||
local isDown = input.IsKeyDown(KEY_G)
|
||||
|
||||
if isDown and not PLUGIN.wasGPressed then
|
||||
PLUGIN.wasGPressed = true
|
||||
|
||||
if not PLUGIN:IsInSquad() then
|
||||
LocalPlayer():Notify("Вы не состоите в отряде")
|
||||
return
|
||||
end
|
||||
|
||||
if CurTime() < PLUGIN.nextMarkerTime then
|
||||
LocalPlayer():Notify("Метка будет доступна через " .. math.ceil(PLUGIN.nextMarkerTime - CurTime()) .. " сек.")
|
||||
return
|
||||
end
|
||||
|
||||
local tr = ply:GetEyeTrace()
|
||||
if not tr.Hit then return end
|
||||
|
||||
PLUGIN.nextMarkerTime = CurTime() + 5
|
||||
|
||||
net.Start("ixSquadPlaceMarker")
|
||||
net.WriteVector(tr.HitPos)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
if not isDown then
|
||||
PLUGIN.wasGPressed = false
|
||||
end
|
||||
end)
|
||||
|
||||
local icon = Material("materials/squads/eye1.png")
|
||||
|
||||
hook.Add("HUDPaint", "ixSquadDrawWorldMarkerHUD", function()
|
||||
local m = PLUGIN.worldMarker
|
||||
if not m then return end
|
||||
|
||||
if CurTime() > m.expire then
|
||||
PLUGIN.worldMarker = nil
|
||||
return
|
||||
end
|
||||
|
||||
local screen = m.pos:ToScreen()
|
||||
|
||||
local dist = LocalPlayer():GetPos():Distance(m.pos)
|
||||
|
||||
local scale = math.Clamp(1 - (dist / 3000), 0.4, 1)
|
||||
|
||||
local size = 96
|
||||
|
||||
surface.SetMaterial(icon)
|
||||
surface.SetDrawColor(255, 255, 255, 255)
|
||||
surface.DrawTexturedRect(screen.x - size/2, screen.y - size/2, size, size)
|
||||
|
||||
surface.SetFont("DermaLarge")
|
||||
local tw, th = surface.GetTextSize(m.name)
|
||||
|
||||
draw.SimpleText(
|
||||
m.name,
|
||||
"DermaLarge",
|
||||
screen.x,
|
||||
screen.y + size/2 + 10,
|
||||
Color(255, 255, 255),
|
||||
TEXT_ALIGN_CENTER,
|
||||
TEXT_ALIGN_TOP,
|
||||
scale
|
||||
)
|
||||
end)
|
||||
21
garrysmod/gamemodes/militaryrp/plugins/squads/sh_plugin.lua
Normal file
21
garrysmod/gamemodes/militaryrp/plugins/squads/sh_plugin.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
local PLUGIN = PLUGIN
|
||||
PLUGIN.name = "Squads System"
|
||||
PLUGIN.author = "MilitaryRP"
|
||||
PLUGIN.description = "Система отрядов для военного сервера"
|
||||
|
||||
ix.config.Add("squadMaxMembers", 16, "Максимальное количество игроков в отряде", nil, {
|
||||
data = {min = 2, max = 32},
|
||||
category = "Squads"
|
||||
})
|
||||
|
||||
ix.config.Add("squadMarkerUpdateRate", 0.5, "Частота обновления маркеров отряда (сек)", nil, {
|
||||
data = {min = 0.1, max = 5},
|
||||
category = "Squads"
|
||||
})
|
||||
|
||||
ix.config.Add("squadMarkerColor", Color(0, 255, 0), "Цвет маркеров союзников", nil, {
|
||||
category = "Squads"
|
||||
})
|
||||
|
||||
ix.util.Include("sv_plugin.lua")
|
||||
ix.util.Include("cl_plugin.lua")
|
||||
692
garrysmod/gamemodes/militaryrp/plugins/squads/sv_plugin.lua
Normal file
692
garrysmod/gamemodes/militaryrp/plugins/squads/sv_plugin.lua
Normal 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)
|
||||
Reference in New Issue
Block a user