```lua
if CLIENT then
    -- Функция для создания уведомления
    local function CreateNotification(text, modelPath)
        -- Создаем панель уведомления
        local frame = vgui.Create("DPanel")
        frame:SetSize(300, 100) -- Размер окна
        frame:SetPos(ScrW(), ScrH() / 2 - 50) -- Начальная позиция за экраном справа
        frame:ParentToHUD() -- Привязка к HUD

        -- Установка кастомного фона
        function frame:Paint(w, h)
            draw.RoundedBox(8, 0, 0, w, h, Color(50, 50, 50, 200)) -- Серый полупрозрачный фон
        end

        -- Добавление текста
        local lbl = vgui.Create("DLabel", frame)
        lbl:SetPos(100, 10)
        lbl:SetSize(180, 80)
        lbl:SetText(text)
        lbl:SetTextColor(Color(255, 255, 255))
        lbl:SetWrap(true)
        lbl:SetContentAlignment(5) -- Центрирование текста

        -- Добавление модели
        local mdl = vgui.Create("DModelPanel", frame)
        mdl:SetPos(10, 10)
        mdl:SetSize(80, 80)
        mdl:SetModel(modelPath or "models/player/kleiner.mdl") -- Модель по умолчанию

        -- Установка позиции камеры модели
        local min, max = mdl.Entity:GetRenderBounds()
        local size = 0
        size = math.max(max.x - min.x, max.y - min.y, max.z - min.z)
        mdl:SetFOV(45)
        mdl:SetCamPos(Vector(size, size, size))
        mdl:SetLookAt((min + max) * 0.5)

        -- Анимация вращения модели
        function mdl:LayoutEntity(entity)
            entity:SetAngles(Angle(0, CurTime() * 30, 0))
        end

        -- Анимация появления окна
        frame:MoveTo(ScrW() - 310, ScrH() / 2 - 50, 0.5, 0, -1, function()
            -- После появления ждем 5 секунд и скрываем
            timer.Simple(5, function()
                if IsValid(frame) then
                    frame:MoveTo(ScrW(), ScrH() / 2 - 50, 0.5, 0, -1, function()
                        if IsValid(frame) then
                            frame:Remove()
                        end
                    end)
                end
            end)
        end)
    end

    -- Получение уведомления от сервера
    net.Receive("ShowNotification", function()
        local text = net.ReadString()
        local model = net.ReadString()
        CreateNotification(text, model)
    end)

    -- Опционально: локальная команда для тестирования уведомления на клиенте
    concommand.Add("show_notification_client", function()
        CreateNotification("Это тестовое уведомление.", "models/player/alyx.mdl")
    end)
end
```
```lua
-- Регистрация сетевого сообщения
if SERVER then
    util.AddNetworkString("ShowNotification")

    -- Функция отправки уведомления конкретному игроку
    local function SendNotification(ply, text, modelPath)
        net.Start("ShowNotification")
            net.WriteString(text)
            net.WriteString(modelPath)
        net.Send(ply)
    end

    -- Функция проверки формата Steam ID
    local function IsValidSteamID(sid)
        -- Проверка формата STEAM_X:Y:Z, где X, Y, Z - цифры
        return string.match(sid, "^STEAM_%d:%d:%d+$") ~= nil
    end

    -- Консольная команда для отправки уведомлений
    -- Использование: show_notification_server <steam_id> <текст> [<путь_к_модели>]
    concommand.Add("show_notification_server", function(ply, cmd, args)
        -- Проверка прав: только администраторы могут использовать команду
        if IsValid(ply) and not ply:IsAdmin() then
            ply:ChatPrint("У вас нет прав для использования этой команды.")
            return
        end

        -- Проверка количества аргументов
        if #args < 2 then
            if IsValid(ply) then
                ply:ChatPrint("Использование: show_notification_server <steam_id> <текст> [<путь_к_модели>]")
            else
                print("Использование: show_notification_server <steam_id> <текст> [<путь_к_модели>]")
            end
            return
        end

        local steamID = args[1]
        -- Используем собственную функцию для проверки Steam ID
        if not IsValidSteamID(steamID) then
            if IsValid(ply) then
                ply:ChatPrint("Неверный формат Steam ID. Пример: STEAM_0:1:123456")
            else
                print("Неверный формат Steam ID. Пример: STEAM_0:1:123456")
            end
            return
        end

        table.remove(args, 1) -- Удаляем Steam ID из аргументов

        -- Определяем, есть ли модель в качестве последнего аргумента
        local model = "models/player/alyx.mdl" -- Модель по умолчанию
        if string.find(args[#args], "^models/") then
            model = args[#args]
            table.remove(args, #args) -- Удаляем модель из аргументов
        end

        local text = table.concat(args, " ")

        -- Поиск игрока по Steam ID
        local target = player.GetBySteamID(steamID)

        if target and IsValid(target) then
            SendNotification(target, text, model)
            if IsValid(ply) then
                ply:ChatPrint("Уведомление отправлено игроку " .. target:Nick())
            else
                print("Уведомление отправлено игроку " .. target:Nick())
            end
        else
            if IsValid(ply) then
                ply:ChatPrint("Игрок с Steam ID \"" .. steamID .. "\" не найден или не онлайн.")
            else
                print("Игрок с Steam ID \"" .. steamID .. "\" не найден или не онлайн.")
            end
        end
    end)
end