add sborka
This commit is contained in:
109
garrysmod/gamemodes/militaryrp/plugins/voice_chat/cl_plugin.lua
Normal file
109
garrysmod/gamemodes/militaryrp/plugins/voice_chat/cl_plugin.lua
Normal file
@@ -0,0 +1,109 @@
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
-- Таблица активных звуков
|
||||
PLUGIN.activeSounds = PLUGIN.activeSounds or {}
|
||||
|
||||
-- Функция для воспроизведения TTS
|
||||
function PLUGIN:PlayTTS(url, speakerName, speakerPos)
|
||||
-- Проверяем, включен ли звук у игрока
|
||||
if not GetConVar("volume"):GetFloat() or GetConVar("volume"):GetFloat() <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Воспроизводим звук через URL
|
||||
sound.PlayURL(url, "3d noblock", function(station, errCode, errStr)
|
||||
if IsValid(station) then
|
||||
-- Устанавливаем позицию звука
|
||||
station:SetPos(speakerPos)
|
||||
|
||||
-- Добавляем 3D эффект
|
||||
station:Set3DEnabled(true)
|
||||
station:Set3DFadeDistance(50, 500)
|
||||
|
||||
-- Громкость зависит от расстояния
|
||||
local radius = ix.config.Get("voiceChatRadius", 200)
|
||||
local distance = LocalPlayer():GetPos():Distance(speakerPos)
|
||||
local volume = math.Clamp(1 - (distance / radius), 0.1, 1)
|
||||
station:SetVolume(volume)
|
||||
|
||||
-- Воспроизводим
|
||||
station:Play()
|
||||
|
||||
-- Сохраняем ссылку на звук
|
||||
PLUGIN.activeSounds[station] = true
|
||||
|
||||
-- Показываем индикатор говорящего
|
||||
local hookID = "ixVoiceChat_" .. tostring(SysTime())
|
||||
hook.Add("HUDPaint", hookID, function()
|
||||
if not IsValid(station) or station:GetState() ~= GMOD_CHANNEL_PLAYING then
|
||||
hook.Remove("HUDPaint", hookID)
|
||||
PLUGIN.activeSounds[station] = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- Рисуем индикатор в правом верхнем углу
|
||||
local w, h = ScrW(), ScrH()
|
||||
local text = "🔊 " .. speakerName
|
||||
|
||||
surface.SetFont("ixMenuButtonFont")
|
||||
local tw, th = surface.GetTextSize(text)
|
||||
|
||||
-- Фон
|
||||
surface.SetDrawColor(0, 0, 0, 200)
|
||||
surface.DrawRect(w - tw - 30, 10, tw + 20, th + 10)
|
||||
|
||||
-- Текст
|
||||
draw.SimpleText(text, "ixMenuButtonFont", w - tw - 20, 15, Color(100, 255, 100), TEXT_ALIGN_LEFT)
|
||||
end)
|
||||
|
||||
-- Автоматически останавливаем через 30 секунд (защита от зависания)
|
||||
timer.Simple(30, function()
|
||||
if IsValid(station) then
|
||||
station:Stop()
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- Ошибка загрузки
|
||||
LocalPlayer():ChatPrint(string.format("[TTS] Ошибка загрузки звука: %s (%s)", errStr or "Unknown", errCode or "0"))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Получение сетевого сообщения
|
||||
net.Receive("ixVoiceChatPlay", function()
|
||||
local url = net.ReadString()
|
||||
local speakerName = net.ReadString()
|
||||
local speakerPos = net.ReadVector()
|
||||
|
||||
PLUGIN:PlayTTS(url, speakerName, speakerPos)
|
||||
end)
|
||||
|
||||
-- Очистка звуков при отключении
|
||||
function PLUGIN:ShutDown()
|
||||
for station, _ in pairs(self.activeSounds) do
|
||||
if IsValid(station) then
|
||||
station:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
self.activeSounds = {}
|
||||
end
|
||||
|
||||
-- Команда для проверки статуса TTS
|
||||
concommand.Add("voice_chat_status", function()
|
||||
local character = LocalPlayer():GetCharacter()
|
||||
if not character then
|
||||
LocalPlayer():ChatPrint("[TTS] У вас нет активного персонажа")
|
||||
return
|
||||
end
|
||||
|
||||
local hasAccess = character:GetData("voice_chat_unlocked", false)
|
||||
|
||||
if hasAccess then
|
||||
LocalPlayer():ChatPrint("[TTS] ✓ У вас есть доступ к говорилке")
|
||||
LocalPlayer():ChatPrint("[TTS] Используйте !tts <текст> для воспроизведения")
|
||||
else
|
||||
LocalPlayer():ChatPrint("[TTS] ✗ У вас нет доступа к говорилке")
|
||||
LocalPlayer():ChatPrint("[TTS] Приобретите её в F4 меню (Другое → Говорилка)")
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,25 @@
|
||||
PLUGIN.name = "Voice Chat TTS"
|
||||
PLUGIN.author = "MilitaryRP"
|
||||
PLUGIN.description = "Система преобразования текста в речь для донатеров"
|
||||
|
||||
ix.config.Add("voiceChatRadius", 200, "Радиус слышимости TTS в метрах", nil, {
|
||||
data = {min = 50, max = 1000},
|
||||
category = "Voice Chat"
|
||||
})
|
||||
|
||||
ix.config.Add("voiceChatCommand", "tts", "Команда для активации TTS (без !)", nil, {
|
||||
category = "Voice Chat"
|
||||
})
|
||||
|
||||
ix.config.Add("voiceChatCooldown", 5, "Задержка между использованием TTS в секундах", nil, {
|
||||
data = {min = 1, max = 60},
|
||||
category = "Voice Chat"
|
||||
})
|
||||
|
||||
ix.config.Add("voiceChatMaxLength", 200, "Максимальная длина сообщения TTS", nil, {
|
||||
data = {min = 50, max = 500},
|
||||
category = "Voice Chat"
|
||||
})
|
||||
|
||||
ix.util.Include("sv_plugin.lua")
|
||||
ix.util.Include("cl_plugin.lua")
|
||||
122
garrysmod/gamemodes/militaryrp/plugins/voice_chat/sv_plugin.lua
Normal file
122
garrysmod/gamemodes/militaryrp/plugins/voice_chat/sv_plugin.lua
Normal file
@@ -0,0 +1,122 @@
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
-- Таблица для отслеживания кулдаунов
|
||||
PLUGIN.voiceChatCooldowns = PLUGIN.voiceChatCooldowns or {}
|
||||
|
||||
-- Функция для проверки доступа к TTS
|
||||
function PLUGIN:CanUseTTS(client)
|
||||
local character = client:GetCharacter()
|
||||
if not character then return false end
|
||||
|
||||
return character:GetData("voice_chat_unlocked", false)
|
||||
end
|
||||
|
||||
-- Функция для получения игроков в радиусе
|
||||
function PLUGIN:GetPlayersInRadius(origin, radius)
|
||||
local players = {}
|
||||
local radiusSqr = radius * radius
|
||||
|
||||
for _, ply in ipairs(player.GetAll()) do
|
||||
if ply:GetPos():DistToSqr(origin) <= radiusSqr then
|
||||
table.insert(players, ply)
|
||||
end
|
||||
end
|
||||
|
||||
return players
|
||||
end
|
||||
|
||||
-- Функция для генерации TTS URL (Google Translate TTS)
|
||||
function PLUGIN:GenerateTTSURL(text)
|
||||
-- Кодируем текст для URL
|
||||
local encoded = text
|
||||
encoded = string.gsub(encoded, "([^%w%s%-%.%_%~])", function(c)
|
||||
return string.format("%%%02X", string.byte(c))
|
||||
end)
|
||||
encoded = string.gsub(encoded, " ", "+")
|
||||
|
||||
-- Google Translate TTS API (бесплатный, без ключа)
|
||||
-- lang=ru - русский язык
|
||||
return string.format("https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=ru&q=%s", encoded)
|
||||
end
|
||||
|
||||
-- Команда чата для TTS
|
||||
function PLUGIN:OnPlayerChat(client, text, isTeam, isDead)
|
||||
local command = ix.config.Get("voiceChatCommand", "tts")
|
||||
local prefix = "!" .. command .. " "
|
||||
|
||||
-- Проверяем, начинается ли сообщение с команды
|
||||
if not string.StartWith(text, prefix) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Проверяем доступ
|
||||
if not self:CanUseTTS(client) then
|
||||
client:Notify("У вас нет доступа к говорилке! Приобретите её в F4 меню.")
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Проверяем кулдаун
|
||||
local cooldownTime = ix.config.Get("voiceChatCooldown", 5)
|
||||
local lastUse = self.voiceChatCooldowns[client:SteamID()] or 0
|
||||
|
||||
if CurTime() - lastUse < cooldownTime then
|
||||
local remaining = math.ceil(cooldownTime - (CurTime() - lastUse))
|
||||
client:Notify(string.format("Подождите %d секунд перед следующим использованием!", remaining))
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Получаем текст сообщения
|
||||
local message = string.sub(text, #prefix + 1)
|
||||
message = string.Trim(message)
|
||||
|
||||
-- Проверяем длину
|
||||
local maxLength = ix.config.Get("voiceChatMaxLength", 200)
|
||||
if #message == 0 then
|
||||
client:Notify("Введите текст после команды !" .. command)
|
||||
return ""
|
||||
end
|
||||
|
||||
if #message > maxLength then
|
||||
client:Notify(string.format("Сообщение слишком длинное! Максимум %d символов.", maxLength))
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Устанавливаем кулдаун
|
||||
self.voiceChatCooldowns[client:SteamID()] = CurTime()
|
||||
|
||||
-- Генерируем URL для TTS
|
||||
local ttsURL = self:GenerateTTSURL(message)
|
||||
|
||||
-- Получаем игроков в радиусе
|
||||
local radius = ix.config.Get("voiceChatRadius", 200)
|
||||
local nearbyPlayers = self:GetPlayersInRadius(client:GetPos(), radius)
|
||||
|
||||
-- Отправляем TTS всем игрокам в радиусе
|
||||
local clientName = client:Name()
|
||||
for _, ply in ipairs(nearbyPlayers) do
|
||||
net.Start("ixVoiceChatPlay")
|
||||
net.WriteString(ttsURL)
|
||||
net.WriteString(clientName)
|
||||
net.WriteVector(client:GetPos())
|
||||
net.Send(ply)
|
||||
end
|
||||
|
||||
-- Показываем сообщение в чате
|
||||
local chatText = string.format("[TTS] %s: %s", clientName, message)
|
||||
for _, ply in ipairs(nearbyPlayers) do
|
||||
ply:ChatPrint(chatText)
|
||||
end
|
||||
|
||||
-- Не показываем оригинальное сообщение
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Очистка кулдаунов при отключении игрока
|
||||
function PLUGIN:PlayerDisconnected(client)
|
||||
self.voiceChatCooldowns[client:SteamID()] = nil
|
||||
end
|
||||
|
||||
-- Сетевой канал для отправки TTS клиентам
|
||||
if SERVER then
|
||||
util.AddNetworkString("ixVoiceChatPlay")
|
||||
end
|
||||
Reference in New Issue
Block a user