```lua
-- cl_realistic_smoke.lua

if CLIENT then
    -- Table to store all active smoke particles
    local SmokeParticles = {}

    -- Table to store all emitters
    local SmokeEmitters = {}

    -- DEBUG MODE
    local DebugMode = false

    -- Smoke settings
    local SmokeSettings = {
        EmitRate = 10,            -- Number of particles emitted per frame per emitter
        MaxParticles = 1000,      -- Maximum number of particles
        Spread = 50,              -- Initial position spread (within EmitVolume)
        InitialVelocity = Vector(0, 0, 50), -- Initial particle velocity (upwards)
        VelocityRandomness = 20,  -- Velocity randomness
        ParticleLifetime = {4, 8},-- Particle lifetime range (seconds)
        ParticleSize = {15, 40},  -- Initial particle size range (units)
        FadeOutTime = 2,          -- Fade-out duration (seconds)
        ColorStart = Color(120, 120, 120, 255), -- Starting color
        ColorEnd = Color(80, 80, 80, 0),         -- Ending color
        Texture = "particle/particle_smokegrenade", -- Particle texture
        Buoyancy = 20,            -- Upward acceleration (buoyancy)
        Turbulence = 10,          -- Turbulence strength
        Wind = Vector(10, 0, 0),  -- Wind direction and strength
        EmitVolume = {            -- Volume within which particles can spawn relative to emitter
            min = Vector(-100, -100, 0),
            max = Vector(100, 100, 100)
        },
        DensityMultiplier = 1,    -- Multiplier for density settings
    }

    -- Function to draw debug information on screen
    local function DrawDebugInfo()
        local w, h = ScrW(), ScrH()
        local text = string.format("Active Smoke Particles: %d | Emitters: %d | Debug Mode: %s", 
            #SmokeParticles, #SmokeEmitters, (DebugMode and "ON" or "OFF"))
        draw.SimpleText(text, "DermaLarge", 10, 10, Color(255, 255, 255, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
    end

    -- SmokeParticle class
    local SmokeParticle = {}
    SmokeParticle.__index = SmokeParticle

    function SmokeParticle:New(pos)
        local self = setmetatable({}, SmokeParticle)
        -- Initial position with spread within the emitter's volume
        self.pos = pos + Vector(
            math.Rand(SmokeSettings.EmitVolume.min.x, SmokeSettings.EmitVolume.max.x),
            math.Rand(SmokeSettings.EmitVolume.min.y, SmokeSettings.EmitVolume.max.y),
            math.Rand(SmokeSettings.EmitVolume.min.z, SmokeSettings.EmitVolume.max.z)
        )
        -- Initial velocity with randomness and turbulence
        self.velocity = SmokeSettings.InitialVelocity + Vector(
            math.Rand(-SmokeSettings.VelocityRandomness, SmokeSettings.VelocityRandomness),
            math.Rand(-SmokeSettings.VelocityRandomness, SmokeSettings.VelocityRandomness),
            math.Rand(-10, 10)
        )
        self.size = math.Rand(SmokeSettings.ParticleSize[1], SmokeSettings.ParticleSize[2])
        self.maxSize = self.size * 3
        self.colorStart = SmokeSettings.ColorStart
        self.colorEnd = SmokeSettings.ColorEnd
        self.alpha = 255
        self.spawnTime = CurTime()
        self.lifetime = math.Rand(SmokeSettings.ParticleLifetime[1], SmokeSettings.ParticleLifetime[2])
        self.texture = SmokeSettings.Texture
        self.collided = false
        return self
    end

    -- Update the particle
    function SmokeParticle:Update(dt)
        if self.collided then
            -- Optionally, handle collision effects here
            return
        end

        -- Add buoyancy (gradual upward acceleration)
        self.velocity = self.velocity + Vector(0, 0, SmokeSettings.Buoyancy * dt)

        -- Add turbulence (random velocity changes)
        local turbulence = Vector(
            math.Rand(-SmokeSettings.Turbulence, SmokeSettings.Turbulence),
            math.Rand(-SmokeSettings.Turbulence, SmokeSettings.Turbulence),
            math.Rand(-5, 5)
        )
        self.velocity = self.velocity + turbulence * dt

        -- Add wind
        self.velocity = self.velocity + SmokeSettings.Wind * dt

        -- Update position
        self.pos = self.pos + self.velocity * dt

        -- Collision check with world
        local tr = util.TraceLine({
            start = self.pos - self.velocity * dt, -- Previous position
            endpos = self.pos,
            mask = MASK_SOLID_BRUSHONLY -- Only check against world geometry
        })

        if tr.Hit then
            self.pos = tr.HitPos
            self.velocity = Vector(0, 0, 0)
            self.collided = true
        end

        -- Expand particle size for diffusion effect
        self.size = math.min(self.size + 15 * dt, self.maxSize)

        -- Fade out alpha smoothly
        local age = CurTime() - self.spawnTime
        if age > (self.lifetime - SmokeSettings.FadeOutTime) then
            local fadeAlpha = 255 * (1 - (age - (self.lifetime - SmokeSettings.FadeOutTime)) / SmokeSettings.FadeOutTime)
            self.alpha = math.Clamp(fadeAlpha, 0, 255)
        end
    end

    -- Draw the particle
    function SmokeParticle:Draw()
        if self.alpha <= 0 then return end

        render.SetMaterial(Material(self.texture))
        -- Linear interpolation of color from start to end based on age
        local age = (CurTime() - self.spawnTime) / self.lifetime
        age = math.Clamp(age, 0, 1)
        local color = Color(
            Lerp(age, self.colorStart.r, self.colorEnd.r),
            Lerp(age, self.colorStart.g, self.colorEnd.g),
            Lerp(age, self.colorStart.b, self.colorEnd.b),
            self.alpha
        )
        render.DrawSprite(self.pos, self.size, self.size, color)
    end

    -- Emitter class
    local SmokeEmitter = {}
    SmokeEmitter.__index = SmokeEmitter

    function SmokeEmitter:New(pos)
        local self = setmetatable({}, SmokeEmitter)
        self.pos = pos
        self.lastEmitTime = 0
        return self
    end

    -- Function to emit new smoke particles from this emitter
    function SmokeEmitter:Emit()
        -- Control emission rate based on density
        local emitInterval = 1 / (SmokeSettings.EmitRate * SmokeSettings.DensityMultiplier)
        if CurTime() - self.lastEmitTime < emitInterval then return end

        for i = 1, SmokeSettings.EmitRate do
            if #SmokeParticles >= SmokeSettings.MaxParticles then break end
            table.insert(SmokeParticles, SmokeParticle:New(self.pos))
        end
        self.lastEmitTime = CurTime()
    end

    -- Function to draw emitter (for debugging)
    function SmokeEmitter:Draw()
        if not DebugMode then return end
        -- Draw a wireframe box representing the emit volume
        local min = SmokeSettings.EmitVolume.min
        local max = SmokeSettings.EmitVolume.max
        render.DrawWireframeBox(self.pos, Angle(0,0,0), min, max, Color(0, 255, 0, 255), true)
    end

    -- Function to add a new emitter
    local function AddEmitter(pos)
        local emitter = SmokeEmitter:New(pos)
        table.insert(SmokeEmitters, emitter)
        print("Smoke emitter added at:", pos)
    end

    -- Function to remove all emitters
    local function RemoveAllEmitters()
        SmokeEmitters = {}
        print("All smoke emitters removed.")
    end

    -- Function to emit particles from all emitters
    local function EmitSmokeParticles()
        for _, emitter in ipairs(SmokeEmitters) do
            emitter:Emit()
        end
    end

    -- Function to update and draw particles
    local function UpdateAndDrawParticles()
        local dt = FrameTime()
        for i = #SmokeParticles, 1, -1 do
            local particle = SmokeParticles[i]
            local age = CurTime() - particle.spawnTime

            if age > particle.lifetime then
                table.remove(SmokeParticles, i)
            else
                particle:Update(dt)
                particle:Draw()
            end
        end

        if DebugMode then
            -- Draw all emitters
            for _, emitter in ipairs(SmokeEmitters) do
                emitter:Draw()
            end

            -- Display debug info
            DrawDebugInfo()
        end
    end

    -- Add hooks
    hook.Add("Think", "RealisticSmokeThink", function()
        EmitSmokeParticles()
    end)

    hook.Add("PostDrawTranslucentRenderables", "RealisticSmokeDraw", function()
        UpdateAndDrawParticles()
    end)

    -- Console commands

    -- Command to add a smoke emitter at a specified position
    -- Usage: add_smoke_emitter x y z
    concommand.Add("add_smoke_emitter", function(ply, cmd, args)
        if #args == 3 then
            local x = tonumber(args[1]) or 0
            local y = tonumber(args[2]) or 0
            local z = tonumber(args[3]) or 0
            local pos = Vector(x, y, z)
            AddEmitter(pos)
        else
            print("Usage: add_smoke_emitter <x> <y> <z>")
        end
    end)

    -- Command to remove all smoke emitters
    -- Usage: remove_smoke_emitters
    concommand.Add("remove_smoke_emitters", function(ply, cmd, args)
        RemoveAllEmitters()
    end)

    -- Command to toggle debug mode
    -- Usage: toggle_smoke_debug
    concommand.Add("toggle_smoke_debug", function(ply, cmd, args)
        DebugMode = not DebugMode
        print("Smoke Debug Mode:", DebugMode and "ON" or "OFF")
    end)

    -- Command to set density multiplier
    -- Usage: set_smoke_density <multiplier>
    concommand.Add("set_smoke_density", function(ply, cmd, args)
        if #args == 1 then
            local multiplier = tonumber(args[1])
            if multiplier and multiplier > 0 then
                SmokeSettings.DensityMultiplier = multiplier
                print("Smoke Density Multiplier set to:", multiplier)
            else
                print("Invalid multiplier. It must be a positive number.")
            end
        else
            print("Usage: set_smoke_density <multiplier>")
        end
    end)

    -- Command to list all current emitters
    -- Usage: list_smoke_emitters
    concommand.Add("list_smoke_emitters", function(ply, cmd, args)
        print("Current Smoke Emitters:")
        if #SmokeEmitters == 0 then
            print("  None")
        else
            for i, emitter in ipairs(SmokeEmitters) do
                print(string.format("  Emitter %d: Pos = %s", i, tostring(emitter.pos)))
            end
        end
    end)

    -- Command to adjust generic smoke settings on the fly
    -- Usage: set_smoke_setting <setting> <value>
    concommand.Add("set_smoke_setting", function(ply, cmd, args)
        if #args < 2 then
            print("Usage: set_smoke_setting <setting> <value>")
            print("Available settings: EmitRate, MaxParticles, Spread, VelocityRandomness, FadeOutTime, DensityMultiplier")
            return
        end

        local setting = args[1]
        local value = tonumber(args[2])

        if not value then
            print("Invalid value. It must be a number.")
            return
        end

        if SmokeSettings[setting] ~= nil then
            SmokeSettings[setting] = value
            print(string.format("Smoke Setting '%s' set to %s", setting, tostring(value)))
        else
            print("Unknown setting:", setting)
            print("Available settings: EmitRate, MaxParticles, Spread, VelocityRandomness, FadeOutTime, DensityMultiplier")
        end
    end)

    -- Optional: Allow setting the emitter position relative to the player
    -- by spawning an emitter at a certain offset
    -- Command: spawn_smoke_relative offset_x offset_y offset_z
    concommand.Add("spawn_smoke_relative", function(ply, cmd, args)
        if not IsValid(ply) then return end
        if #args == 3 then
            local offsetX = tonumber(args[1]) or 0
            local offsetY = tonumber(args[2]) or 0
            local offsetZ = tonumber(args[3]) or 0
            local pos = ply:GetPos() + Vector(offsetX, offsetY, offsetZ)
            AddEmitter(pos)
        else
            print("Usage: spawn_smoke_relative <offset_x> <offset_y> <offset_z>")
        end
    end)

    -- Initialization: Optionally, add a default emitter or wait for user to add emitters
    hook.Add("InitPostEntity", "InitializeSmokeEmitters", function()
        -- Example: Add a default emitter at origin
        -- Uncomment the line below to add a default emitter
        -- AddEmitter(Vector(0, 0, 0))
    end)
end
```
Структурируй код, оптимизируй его, произведи рефакторинг и код ревью, напиши полный код с списком изменений